1 /*! jQuery UI - v1.12.1 - 2016-09-14
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-1-7.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 */
7 if ( typeof define === "function" && define.amd ) {
9 // AMD. Register as an anonymous module.
10 define([ "jquery" ], factory );
20 var version = $.ui.version = "1.12.1";
24 * jQuery UI Widget 1.12.1
27 * Copyright jQuery Foundation and other contributors
28 * Released under the MIT license.
29 * http://jquery.org/license
34 //>>description: Provides a factory for creating stateful widgets with a common API.
35 //>>docs: http://api.jqueryui.com/jQuery.widget/
36 //>>demos: http://jqueryui.com/widget/
41 var widgetSlice = Array.prototype.slice;
43 $.cleanData = ( function( orig ) {
44 return function( elems ) {
46 for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) {
49 // Only trigger remove when necessary to save time
50 events = $._data( elem, "events" );
51 if ( events && events.remove ) {
52 $( elem ).triggerHandler( "remove" );
55 // Http://bugs.jquery.com/ticket/8235
62 $.widget = function( name, base, prototype ) {
63 var existingConstructor, constructor, basePrototype;
65 // ProxiedPrototype allows the provided prototype to remain unmodified
66 // so that it can be used as a mixin for multiple widgets (#8876)
67 var proxiedPrototype = {};
69 var namespace = name.split( "." )[ 0 ];
70 name = name.split( "." )[ 1 ];
71 var fullName = namespace + "-" + name;
78 if ( $.isArray( prototype ) ) {
79 prototype = $.extend.apply( null, [ {} ].concat( prototype ) );
82 // Create selector for plugin
83 $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
84 return !!$.data( elem, fullName );
87 $[ namespace ] = $[ namespace ] || {};
88 existingConstructor = $[ namespace ][ name ];
89 constructor = $[ namespace ][ name ] = function( options, element ) {
91 // Allow instantiation without "new" keyword
92 if ( !this._createWidget ) {
93 return new constructor( options, element );
96 // Allow instantiation without initializing for simple inheritance
97 // must use "new" keyword (the code above always passes args)
98 if ( arguments.length ) {
99 this._createWidget( options, element );
103 // Extend with the existing constructor to carry over any static properties
104 $.extend( constructor, existingConstructor, {
105 version: prototype.version,
107 // Copy the object used to create the prototype in case we need to
108 // redefine the widget later
109 _proto: $.extend( {}, prototype ),
111 // Track widgets that inherit from this widget in case this widget is
112 // redefined after a widget inherits from it
113 _childConstructors: []
116 basePrototype = new base();
118 // We need to make the options hash a property directly on the new instance
119 // otherwise we'll modify the options hash on the prototype that we're
121 basePrototype.options = $.widget.extend( {}, basePrototype.options );
122 $.each( prototype, function( prop, value ) {
123 if ( !$.isFunction( value ) ) {
124 proxiedPrototype[ prop ] = value;
127 proxiedPrototype[ prop ] = ( function() {
129 return base.prototype[ prop ].apply( this, arguments );
132 function _superApply( args ) {
133 return base.prototype[ prop ].apply( this, args );
137 var __super = this._super;
138 var __superApply = this._superApply;
141 this._super = _super;
142 this._superApply = _superApply;
144 returnValue = value.apply( this, arguments );
146 this._super = __super;
147 this._superApply = __superApply;
153 constructor.prototype = $.widget.extend( basePrototype, {
155 // TODO: remove support for widgetEventPrefix
156 // always use the name + a colon as the prefix, e.g., draggable:start
157 // don't prefix for widgets that aren't DOM-based
158 widgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name
159 }, proxiedPrototype, {
160 constructor: constructor,
161 namespace: namespace,
163 widgetFullName: fullName
166 // If this widget is being redefined then we need to find all widgets that
167 // are inheriting from it and redefine all of them so that they inherit from
168 // the new version of this widget. We're essentially trying to replace one
169 // level in the prototype chain.
170 if ( existingConstructor ) {
171 $.each( existingConstructor._childConstructors, function( i, child ) {
172 var childPrototype = child.prototype;
174 // Redefine the child widget using the same prototype that was
175 // originally used, but inherit from the new version of the base
176 $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor,
180 // Remove the list of existing child constructors from the old constructor
181 // so the old child constructors can be garbage collected
182 delete existingConstructor._childConstructors;
184 base._childConstructors.push( constructor );
187 $.widget.bridge( name, constructor );
192 $.widget.extend = function( target ) {
193 var input = widgetSlice.call( arguments, 1 );
195 var inputLength = input.length;
199 for ( ; inputIndex < inputLength; inputIndex++ ) {
200 for ( key in input[ inputIndex ] ) {
201 value = input[ inputIndex ][ key ];
202 if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
205 if ( $.isPlainObject( value ) ) {
206 target[ key ] = $.isPlainObject( target[ key ] ) ?
207 $.widget.extend( {}, target[ key ], value ) :
209 // Don't extend strings, arrays, etc. with objects
210 $.widget.extend( {}, value );
212 // Copy everything else by reference
214 target[ key ] = value;
222 $.widget.bridge = function( name, object ) {
223 var fullName = object.prototype.widgetFullName || name;
224 $.fn[ name ] = function( options ) {
225 var isMethodCall = typeof options === "string";
226 var args = widgetSlice.call( arguments, 1 );
227 var returnValue = this;
229 if ( isMethodCall ) {
231 // If this is an empty collection, we need to have the instance method
232 // return undefined instead of the jQuery instance
233 if ( !this.length && options === "instance" ) {
234 returnValue = undefined;
236 this.each( function() {
238 var instance = $.data( this, fullName );
240 if ( options === "instance" ) {
241 returnValue = instance;
246 return $.error( "cannot call methods on " + name +
247 " prior to initialization; " +
248 "attempted to call method '" + options + "'" );
251 if ( !$.isFunction( instance[ options ] ) || 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 processClassString( classes, checkOption ) {
514 for ( i = 0; i < classes.length; i++ ) {
515 current = that.classesElementLookup[ classes[ i ] ] || $();
517 current = $( $.unique( current.get().concat( options.element.get() ) ) );
519 current = $( current.not( options.element ).get() );
521 that.classesElementLookup[ classes[ i ] ] = current;
522 full.push( classes[ i ] );
523 if ( checkOption && options.classes[ classes[ i ] ] ) {
524 full.push( options.classes[ classes[ i ] ] );
529 this._on( options.element, {
530 "remove": "_untrackClassesElement"
533 if ( options.keys ) {
534 processClassString( options.keys.match( /\S+/g ) || [], true );
536 if ( options.extra ) {
537 processClassString( options.extra.match( /\S+/g ) || [] );
540 return full.join( " " );
543 _untrackClassesElement: function( event ) {
545 $.each( that.classesElementLookup, function( key, value ) {
546 if ( $.inArray( event.target, value ) !== -1 ) {
547 that.classesElementLookup[ key ] = $( value.not( event.target ).get() );
552 _removeClass: function( element, keys, extra ) {
553 return this._toggleClass( element, keys, extra, false );
556 _addClass: function( element, keys, extra ) {
557 return this._toggleClass( element, keys, extra, true );
560 _toggleClass: function( element, keys, extra, add ) {
561 add = ( typeof add === "boolean" ) ? add : extra;
562 var shift = ( typeof element === "string" || element === null ),
564 extra: shift ? keys : extra,
565 keys: shift ? element : keys,
566 element: shift ? this.element : element,
569 options.element.toggleClass( this._classes( options ), add );
573 _on: function( suppressDisabledCheck, element, handlers ) {
577 // No suppressDisabledCheck flag, shuffle arguments
578 if ( typeof suppressDisabledCheck !== "boolean" ) {
580 element = suppressDisabledCheck;
581 suppressDisabledCheck = false;
584 // No element argument, shuffle and use this.element
587 element = this.element;
588 delegateElement = this.widget();
590 element = delegateElement = $( element );
591 this.bindings = this.bindings.add( element );
594 $.each( handlers, function( event, handler ) {
595 function handlerProxy() {
597 // Allow widgets to customize the disabled handling
598 // - disabled as an array instead of boolean
599 // - disabled class as method for disabling individual parts
600 if ( !suppressDisabledCheck &&
601 ( instance.options.disabled === true ||
602 $( this ).hasClass( "ui-state-disabled" ) ) ) {
605 return ( typeof handler === "string" ? instance[ handler ] : handler )
606 .apply( instance, arguments );
609 // Copy the guid so direct unbinding works
610 if ( typeof handler !== "string" ) {
611 handlerProxy.guid = handler.guid =
612 handler.guid || handlerProxy.guid || $.guid++;
615 var match = event.match( /^([\w:-]*)\s*(.*)$/ );
616 var eventName = match[ 1 ] + instance.eventNamespace;
617 var selector = match[ 2 ];
620 delegateElement.on( eventName, selector, handlerProxy );
622 element.on( eventName, handlerProxy );
627 _off: function( element, eventName ) {
628 eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) +
630 element.off( eventName ).off( eventName );
632 // Clear the stack to avoid memory leaks (#10056)
633 this.bindings = $( this.bindings.not( element ).get() );
634 this.focusable = $( this.focusable.not( element ).get() );
635 this.hoverable = $( this.hoverable.not( element ).get() );
638 _delay: function( handler, delay ) {
639 function handlerProxy() {
640 return ( typeof handler === "string" ? instance[ handler ] : handler )
641 .apply( instance, arguments );
644 return setTimeout( handlerProxy, delay || 0 );
647 _hoverable: function( element ) {
648 this.hoverable = this.hoverable.add( element );
650 mouseenter: function( event ) {
651 this._addClass( $( event.currentTarget ), null, "ui-state-hover" );
653 mouseleave: function( event ) {
654 this._removeClass( $( event.currentTarget ), null, "ui-state-hover" );
659 _focusable: function( element ) {
660 this.focusable = this.focusable.add( element );
662 focusin: function( event ) {
663 this._addClass( $( event.currentTarget ), null, "ui-state-focus" );
665 focusout: function( event ) {
666 this._removeClass( $( event.currentTarget ), null, "ui-state-focus" );
671 _trigger: function( type, event, data ) {
673 var callback = this.options[ type ];
676 event = $.Event( event );
677 event.type = ( type === this.widgetEventPrefix ?
679 this.widgetEventPrefix + type ).toLowerCase();
681 // The original event may come from any element
682 // so we need to reset the target on the new event
683 event.target = this.element[ 0 ];
685 // Copy original event properties over to the new event
686 orig = event.originalEvent;
688 for ( prop in orig ) {
689 if ( !( prop in event ) ) {
690 event[ prop ] = orig[ prop ];
695 this.element.trigger( event, data );
696 return !( $.isFunction( callback ) &&
697 callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false ||
698 event.isDefaultPrevented() );
702 $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
703 $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
704 if ( typeof options === "string" ) {
705 options = { effect: options };
709 var effectName = !options ?
711 options === true || typeof options === "number" ?
713 options.effect || defaultEffect;
715 options = options || {};
716 if ( typeof options === "number" ) {
717 options = { duration: options };
720 hasOptions = !$.isEmptyObject( options );
721 options.complete = callback;
723 if ( options.delay ) {
724 element.delay( options.delay );
727 if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
728 element[ method ]( options );
729 } else if ( effectName !== method && element[ effectName ] ) {
730 element[ effectName ]( options.duration, options.easing, callback );
732 element.queue( function( next ) {
733 $( this )[ method ]();
735 callback.call( element[ 0 ] );
743 var widget = $.widget;
747 * jQuery UI Position 1.12.1
748 * http://jqueryui.com
750 * Copyright jQuery Foundation and other contributors
751 * Released under the MIT license.
752 * http://jquery.org/license
754 * http://api.jqueryui.com/position/
759 //>>description: Positions elements relative to other elements.
760 //>>docs: http://api.jqueryui.com/position/
761 //>>demos: http://jqueryui.com/position/
765 var cachedScrollbarWidth,
768 rhorizontal = /left|center|right/,
769 rvertical = /top|center|bottom/,
770 roffset = /[\+\-]\d+(\.[\d]+)?%?/,
773 _position = $.fn.position;
775 function getOffsets( offsets, width, height ) {
777 parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
778 parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
782 function parseCss( element, property ) {
783 return parseInt( $.css( element, property ), 10 ) || 0;
786 function getDimensions( elem ) {
788 if ( raw.nodeType === 9 ) {
791 height: elem.height(),
792 offset: { top: 0, left: 0 }
795 if ( $.isWindow( raw ) ) {
798 height: elem.height(),
799 offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
802 if ( raw.preventDefault ) {
806 offset: { top: raw.pageY, left: raw.pageX }
810 width: elem.outerWidth(),
811 height: elem.outerHeight(),
812 offset: elem.offset()
817 scrollbarWidth: function() {
818 if ( cachedScrollbarWidth !== undefined ) {
819 return cachedScrollbarWidth;
823 "style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'>" +
824 "<div style='height:100px;width:auto;'></div></div>" ),
825 innerDiv = div.children()[ 0 ];
827 $( "body" ).append( div );
828 w1 = innerDiv.offsetWidth;
829 div.css( "overflow", "scroll" );
831 w2 = innerDiv.offsetWidth;
834 w2 = div[ 0 ].clientWidth;
839 return ( cachedScrollbarWidth = w1 - w2 );
841 getScrollInfo: function( within ) {
842 var overflowX = within.isWindow || within.isDocument ? "" :
843 within.element.css( "overflow-x" ),
844 overflowY = within.isWindow || within.isDocument ? "" :
845 within.element.css( "overflow-y" ),
846 hasOverflowX = overflowX === "scroll" ||
847 ( overflowX === "auto" && within.width < within.element[ 0 ].scrollWidth ),
848 hasOverflowY = overflowY === "scroll" ||
849 ( overflowY === "auto" && within.height < within.element[ 0 ].scrollHeight );
851 width: hasOverflowY ? $.position.scrollbarWidth() : 0,
852 height: hasOverflowX ? $.position.scrollbarWidth() : 0
855 getWithinInfo: function( element ) {
856 var withinElement = $( element || window ),
857 isWindow = $.isWindow( withinElement[ 0 ] ),
858 isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9,
859 hasOffset = !isWindow && !isDocument;
861 element: withinElement,
863 isDocument: isDocument,
864 offset: hasOffset ? $( element ).offset() : { left: 0, top: 0 },
865 scrollLeft: withinElement.scrollLeft(),
866 scrollTop: withinElement.scrollTop(),
867 width: withinElement.outerWidth(),
868 height: withinElement.outerHeight()
873 $.fn.position = function( options ) {
874 if ( !options || !options.of ) {
875 return _position.apply( this, arguments );
878 // Make a copy, we don't want to modify arguments
879 options = $.extend( {}, options );
881 var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
882 target = $( options.of ),
883 within = $.position.getWithinInfo( options.within ),
884 scrollInfo = $.position.getScrollInfo( within ),
885 collision = ( options.collision || "flip" ).split( " " ),
888 dimensions = getDimensions( target );
889 if ( target[ 0 ].preventDefault ) {
891 // Force left top to allow flipping
892 options.at = "left top";
894 targetWidth = dimensions.width;
895 targetHeight = dimensions.height;
896 targetOffset = dimensions.offset;
898 // Clone to reuse original targetOffset later
899 basePosition = $.extend( {}, targetOffset );
901 // Force my and at to have valid horizontal and vertical positions
902 // if a value is missing or invalid, it will be converted to center
903 $.each( [ "my", "at" ], function() {
904 var pos = ( options[ this ] || "" ).split( " " ),
908 if ( pos.length === 1 ) {
909 pos = rhorizontal.test( pos[ 0 ] ) ?
910 pos.concat( [ "center" ] ) :
911 rvertical.test( pos[ 0 ] ) ?
912 [ "center" ].concat( pos ) :
913 [ "center", "center" ];
915 pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
916 pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
919 horizontalOffset = roffset.exec( pos[ 0 ] );
920 verticalOffset = roffset.exec( pos[ 1 ] );
922 horizontalOffset ? horizontalOffset[ 0 ] : 0,
923 verticalOffset ? verticalOffset[ 0 ] : 0
926 // Reduce to just the positions without the offsets
928 rposition.exec( pos[ 0 ] )[ 0 ],
929 rposition.exec( pos[ 1 ] )[ 0 ]
933 // Normalize collision option
934 if ( collision.length === 1 ) {
935 collision[ 1 ] = collision[ 0 ];
938 if ( options.at[ 0 ] === "right" ) {
939 basePosition.left += targetWidth;
940 } else if ( options.at[ 0 ] === "center" ) {
941 basePosition.left += targetWidth / 2;
944 if ( options.at[ 1 ] === "bottom" ) {
945 basePosition.top += targetHeight;
946 } else if ( options.at[ 1 ] === "center" ) {
947 basePosition.top += targetHeight / 2;
950 atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
951 basePosition.left += atOffset[ 0 ];
952 basePosition.top += atOffset[ 1 ];
954 return this.each( function() {
955 var collisionPosition, using,
957 elemWidth = elem.outerWidth(),
958 elemHeight = elem.outerHeight(),
959 marginLeft = parseCss( this, "marginLeft" ),
960 marginTop = parseCss( this, "marginTop" ),
961 collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) +
963 collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) +
965 position = $.extend( {}, basePosition ),
966 myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
968 if ( options.my[ 0 ] === "right" ) {
969 position.left -= elemWidth;
970 } else if ( options.my[ 0 ] === "center" ) {
971 position.left -= elemWidth / 2;
974 if ( options.my[ 1 ] === "bottom" ) {
975 position.top -= elemHeight;
976 } else if ( options.my[ 1 ] === "center" ) {
977 position.top -= elemHeight / 2;
980 position.left += myOffset[ 0 ];
981 position.top += myOffset[ 1 ];
983 collisionPosition = {
984 marginLeft: marginLeft,
988 $.each( [ "left", "top" ], function( i, dir ) {
989 if ( $.ui.position[ collision[ i ] ] ) {
990 $.ui.position[ collision[ i ] ][ dir ]( position, {
991 targetWidth: targetWidth,
992 targetHeight: targetHeight,
993 elemWidth: elemWidth,
994 elemHeight: elemHeight,
995 collisionPosition: collisionPosition,
996 collisionWidth: collisionWidth,
997 collisionHeight: collisionHeight,
998 offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
1007 if ( options.using ) {
1009 // Adds feedback as second argument to using callback, if present
1010 using = function( props ) {
1011 var left = targetOffset.left - position.left,
1012 right = left + targetWidth - elemWidth,
1013 top = targetOffset.top - position.top,
1014 bottom = top + targetHeight - elemHeight,
1018 left: targetOffset.left,
1019 top: targetOffset.top,
1021 height: targetHeight
1025 left: position.left,
1030 horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
1031 vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
1033 if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
1034 feedback.horizontal = "center";
1036 if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
1037 feedback.vertical = "middle";
1039 if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
1040 feedback.important = "horizontal";
1042 feedback.important = "vertical";
1044 options.using.call( this, props, feedback );
1048 elem.offset( $.extend( position, { using: using } ) );
1054 left: function( position, data ) {
1055 var within = data.within,
1056 withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
1057 outerWidth = within.width,
1058 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
1059 overLeft = withinOffset - collisionPosLeft,
1060 overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
1063 // Element is wider than within
1064 if ( data.collisionWidth > outerWidth ) {
1066 // Element is initially over the left side of within
1067 if ( overLeft > 0 && overRight <= 0 ) {
1068 newOverRight = position.left + overLeft + data.collisionWidth - outerWidth -
1070 position.left += overLeft - newOverRight;
1072 // Element is initially over right side of within
1073 } else if ( overRight > 0 && overLeft <= 0 ) {
1074 position.left = withinOffset;
1076 // Element is initially over both left and right sides of within
1078 if ( overLeft > overRight ) {
1079 position.left = withinOffset + outerWidth - data.collisionWidth;
1081 position.left = withinOffset;
1085 // Too far left -> align with left edge
1086 } else if ( overLeft > 0 ) {
1087 position.left += overLeft;
1089 // Too far right -> align with right edge
1090 } else if ( overRight > 0 ) {
1091 position.left -= overRight;
1093 // Adjust based on position and margin
1095 position.left = max( position.left - collisionPosLeft, position.left );
1098 top: function( position, data ) {
1099 var within = data.within,
1100 withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
1101 outerHeight = data.within.height,
1102 collisionPosTop = position.top - data.collisionPosition.marginTop,
1103 overTop = withinOffset - collisionPosTop,
1104 overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
1107 // Element is taller than within
1108 if ( data.collisionHeight > outerHeight ) {
1110 // Element is initially over the top of within
1111 if ( overTop > 0 && overBottom <= 0 ) {
1112 newOverBottom = position.top + overTop + data.collisionHeight - outerHeight -
1114 position.top += overTop - newOverBottom;
1116 // Element is initially over bottom of within
1117 } else if ( overBottom > 0 && overTop <= 0 ) {
1118 position.top = withinOffset;
1120 // Element is initially over both top and bottom of within
1122 if ( overTop > overBottom ) {
1123 position.top = withinOffset + outerHeight - data.collisionHeight;
1125 position.top = withinOffset;
1129 // Too far up -> align with top
1130 } else if ( overTop > 0 ) {
1131 position.top += overTop;
1133 // Too far down -> align with bottom edge
1134 } else if ( overBottom > 0 ) {
1135 position.top -= overBottom;
1137 // Adjust based on position and margin
1139 position.top = max( position.top - collisionPosTop, position.top );
1144 left: function( position, data ) {
1145 var within = data.within,
1146 withinOffset = within.offset.left + within.scrollLeft,
1147 outerWidth = within.width,
1148 offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
1149 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
1150 overLeft = collisionPosLeft - offsetLeft,
1151 overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
1152 myOffset = data.my[ 0 ] === "left" ?
1154 data.my[ 0 ] === "right" ?
1157 atOffset = data.at[ 0 ] === "left" ?
1159 data.at[ 0 ] === "right" ?
1162 offset = -2 * data.offset[ 0 ],
1166 if ( overLeft < 0 ) {
1167 newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth -
1168 outerWidth - withinOffset;
1169 if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
1170 position.left += myOffset + atOffset + offset;
1172 } else if ( overRight > 0 ) {
1173 newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset +
1174 atOffset + offset - offsetLeft;
1175 if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
1176 position.left += myOffset + atOffset + offset;
1180 top: function( position, data ) {
1181 var within = data.within,
1182 withinOffset = within.offset.top + within.scrollTop,
1183 outerHeight = within.height,
1184 offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
1185 collisionPosTop = position.top - data.collisionPosition.marginTop,
1186 overTop = collisionPosTop - offsetTop,
1187 overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
1188 top = data.my[ 1 ] === "top",
1191 data.my[ 1 ] === "bottom" ?
1194 atOffset = data.at[ 1 ] === "top" ?
1196 data.at[ 1 ] === "bottom" ?
1197 -data.targetHeight :
1199 offset = -2 * data.offset[ 1 ],
1202 if ( overTop < 0 ) {
1203 newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight -
1204 outerHeight - withinOffset;
1205 if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) {
1206 position.top += myOffset + atOffset + offset;
1208 } else if ( overBottom > 0 ) {
1209 newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset +
1211 if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) {
1212 position.top += myOffset + atOffset + offset;
1219 $.ui.position.flip.left.apply( this, arguments );
1220 $.ui.position.fit.left.apply( this, arguments );
1223 $.ui.position.flip.top.apply( this, arguments );
1224 $.ui.position.fit.top.apply( this, arguments );
1231 var position = $.ui.position;
1235 * jQuery UI :data 1.12.1
1236 * http://jqueryui.com
1238 * Copyright jQuery Foundation and other contributors
1239 * Released under the MIT license.
1240 * http://jquery.org/license
1243 //>>label: :data Selector
1245 //>>description: Selects elements which have data stored under the specified key.
1246 //>>docs: http://api.jqueryui.com/data-selector/
1249 var data = $.extend( $.expr[ ":" ], {
1250 data: $.expr.createPseudo ?
1251 $.expr.createPseudo( function( dataName ) {
1252 return function( elem ) {
1253 return !!$.data( elem, dataName );
1257 // Support: jQuery <1.8
1258 function( elem, i, match ) {
1259 return !!$.data( elem, match[ 3 ] );
1264 * jQuery UI Disable Selection 1.12.1
1265 * http://jqueryui.com
1267 * Copyright jQuery Foundation and other contributors
1268 * Released under the MIT license.
1269 * http://jquery.org/license
1272 //>>label: disableSelection
1274 //>>description: Disable selection of text content within the set of matched elements.
1275 //>>docs: http://api.jqueryui.com/disableSelection/
1277 // This file is deprecated
1280 var disableSelection = $.fn.extend( {
1281 disableSelection: ( function() {
1282 var eventType = "onselectstart" in document.createElement( "div" ) ?
1287 return this.on( eventType + ".ui-disableSelection", function( event ) {
1288 event.preventDefault();
1293 enableSelection: function() {
1294 return this.off( ".ui-disableSelection" );
1300 * jQuery UI Effects 1.12.1
1301 * http://jqueryui.com
1303 * Copyright jQuery Foundation and other contributors
1304 * Released under the MIT license.
1305 * http://jquery.org/license
1308 //>>label: Effects Core
1310 // jscs:disable maximumLineLength
1311 //>>description: Extends the internal jQuery effects. Includes morphing and easing. Required by all other effects.
1312 // jscs:enable maximumLineLength
1313 //>>docs: http://api.jqueryui.com/category/effects-core/
1314 //>>demos: http://jqueryui.com/effect/
1318 var dataSpace = "ui-effects-",
1319 dataSpaceStyle = "ui-effects-style",
1320 dataSpaceAnimated = "ui-effects-animated",
1322 // Create a local jQuery because jQuery Color relies on it and the
1323 // global may not exist with AMD and a custom build (#10199)
1331 * jQuery Color Animations v2.1.2
1332 * https://github.com/jquery/jquery-color
1334 * Copyright 2014 jQuery Foundation and other contributors
1335 * Released under the MIT license.
1336 * http://jquery.org/license
1338 * Date: Wed Jan 16 08:47:09 2013 -0600
1340 ( function( jQuery, undefined ) {
1342 var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor " +
1343 "borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
1345 // Plusequals test for += 100 -= 100
1346 rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
1348 // A set of RE's that can match strings and generate color tuples.
1350 re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
1351 parse: function( execResult ) {
1360 re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
1361 parse: function( execResult ) {
1363 execResult[ 1 ] * 2.55,
1364 execResult[ 2 ] * 2.55,
1365 execResult[ 3 ] * 2.55,
1371 // This regex ignores A-F because it's compared against an already lowercased string
1372 re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
1373 parse: function( execResult ) {
1375 parseInt( execResult[ 1 ], 16 ),
1376 parseInt( execResult[ 2 ], 16 ),
1377 parseInt( execResult[ 3 ], 16 )
1382 // This regex ignores A-F because it's compared against an already lowercased string
1383 re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
1384 parse: function( execResult ) {
1386 parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
1387 parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
1388 parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
1392 re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
1394 parse: function( execResult ) {
1397 execResult[ 2 ] / 100,
1398 execResult[ 3 ] / 100,
1405 color = jQuery.Color = function( color, green, blue, alpha ) {
1406 return new jQuery.Color.fn.parse( color, green, blue, alpha );
1456 support = color.support = {},
1458 // Element for support tests
1459 supportElem = jQuery( "<p>" )[ 0 ],
1461 // Colors = jQuery.Color.names
1464 // Local aliases of functions called often
1467 // Determine rgba support immediately
1468 supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
1469 support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
1471 // Define cache name and alpha properties
1472 // for rgba and hsla spaces
1473 each( spaces, function( spaceName, space ) {
1474 space.cache = "_" + spaceName;
1475 space.props.alpha = {
1482 function clamp( value, prop, allowEmpty ) {
1483 var type = propTypes[ prop.type ] || {};
1485 if ( value == null ) {
1486 return ( allowEmpty || !prop.def ) ? null : prop.def;
1489 // ~~ is an short way of doing floor for positive numbers
1490 value = type.floor ? ~~value : parseFloat( value );
1492 // IE will pass in empty strings as value for alpha,
1493 // which will hit this case
1494 if ( isNaN( value ) ) {
1500 // We add mod before modding to make sure that negatives values
1501 // get converted properly: -10 -> 350
1502 return ( value + type.mod ) % type.mod;
1505 // For now all property types without mod have min and max
1506 return 0 > value ? 0 : type.max < value ? type.max : value;
1509 function stringParse( string ) {
1511 rgba = inst._rgba = [];
1513 string = string.toLowerCase();
1515 each( stringParsers, function( i, parser ) {
1517 match = parser.re.exec( string ),
1518 values = match && parser.parse( match ),
1519 spaceName = parser.space || "rgba";
1522 parsed = inst[ spaceName ]( values );
1524 // If this was an rgba parse the assignment might happen twice
1526 inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
1527 rgba = inst._rgba = parsed._rgba;
1529 // Exit each( stringParsers ) here because we matched
1534 // Found a stringParser that handled it
1535 if ( rgba.length ) {
1537 // If this came from a parsed string, force "transparent" when alpha is 0
1538 // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
1539 if ( rgba.join() === "0,0,0,0" ) {
1540 jQuery.extend( rgba, colors.transparent );
1546 return colors[ string ];
1549 color.fn = jQuery.extend( color.prototype, {
1550 parse: function( red, green, blue, alpha ) {
1551 if ( red === undefined ) {
1552 this._rgba = [ null, null, null, null ];
1555 if ( red.jquery || red.nodeType ) {
1556 red = jQuery( red ).css( green );
1561 type = jQuery.type( red ),
1562 rgba = this._rgba = [];
1564 // More than 1 argument specified - assume ( red, green, blue, alpha )
1565 if ( green !== undefined ) {
1566 red = [ red, green, blue, alpha ];
1570 if ( type === "string" ) {
1571 return this.parse( stringParse( red ) || colors._default );
1574 if ( type === "array" ) {
1575 each( spaces.rgba.props, function( key, prop ) {
1576 rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
1581 if ( type === "object" ) {
1582 if ( red instanceof color ) {
1583 each( spaces, function( spaceName, space ) {
1584 if ( red[ space.cache ] ) {
1585 inst[ space.cache ] = red[ space.cache ].slice();
1589 each( spaces, function( spaceName, space ) {
1590 var cache = space.cache;
1591 each( space.props, function( key, prop ) {
1593 // If the cache doesn't exist, and we know how to convert
1594 if ( !inst[ cache ] && space.to ) {
1596 // If the value was null, we don't need to copy it
1597 // if the key was alpha, we don't need to copy it either
1598 if ( key === "alpha" || red[ key ] == null ) {
1601 inst[ cache ] = space.to( inst._rgba );
1604 // This is the only case where we allow nulls for ALL properties.
1605 // call clamp with alwaysAllowEmpty
1606 inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
1609 // Everything defined but alpha?
1610 if ( inst[ cache ] &&
1611 jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
1613 // Use the default of 1
1614 inst[ cache ][ 3 ] = 1;
1616 inst._rgba = space.from( inst[ cache ] );
1624 is: function( compare ) {
1625 var is = color( compare ),
1629 each( spaces, function( _, space ) {
1631 isCache = is[ space.cache ];
1633 localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
1634 each( space.props, function( _, prop ) {
1635 if ( isCache[ prop.idx ] != null ) {
1636 same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
1645 _space: function() {
1648 each( spaces, function( spaceName, space ) {
1649 if ( inst[ space.cache ] ) {
1650 used.push( spaceName );
1655 transition: function( other, distance ) {
1656 var end = color( other ),
1657 spaceName = end._space(),
1658 space = spaces[ spaceName ],
1659 startColor = this.alpha() === 0 ? color( "transparent" ) : this,
1660 start = startColor[ space.cache ] || space.to( startColor._rgba ),
1661 result = start.slice();
1663 end = end[ space.cache ];
1664 each( space.props, function( key, prop ) {
1665 var index = prop.idx,
1666 startValue = start[ index ],
1667 endValue = end[ index ],
1668 type = propTypes[ prop.type ] || {};
1670 // If null, don't override start value
1671 if ( endValue === null ) {
1675 // If null - use end
1676 if ( startValue === null ) {
1677 result[ index ] = endValue;
1680 if ( endValue - startValue > type.mod / 2 ) {
1681 startValue += type.mod;
1682 } else if ( startValue - endValue > type.mod / 2 ) {
1683 startValue -= type.mod;
1686 result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
1689 return this[ spaceName ]( result );
1691 blend: function( opaque ) {
1693 // If we are already opaque - return ourself
1694 if ( this._rgba[ 3 ] === 1 ) {
1698 var rgb = this._rgba.slice(),
1700 blend = color( opaque )._rgba;
1702 return color( jQuery.map( rgb, function( v, i ) {
1703 return ( 1 - a ) * blend[ i ] + a * v;
1706 toRgbaString: function() {
1707 var prefix = "rgba(",
1708 rgba = jQuery.map( this._rgba, function( v, i ) {
1709 return v == null ? ( i > 2 ? 1 : 0 ) : v;
1712 if ( rgba[ 3 ] === 1 ) {
1717 return prefix + rgba.join() + ")";
1719 toHslaString: function() {
1720 var prefix = "hsla(",
1721 hsla = jQuery.map( this.hsla(), function( v, i ) {
1728 v = Math.round( v * 100 ) + "%";
1733 if ( hsla[ 3 ] === 1 ) {
1737 return prefix + hsla.join() + ")";
1739 toHexString: function( includeAlpha ) {
1740 var rgba = this._rgba.slice(),
1743 if ( includeAlpha ) {
1744 rgba.push( ~~( alpha * 255 ) );
1747 return "#" + jQuery.map( rgba, function( v ) {
1749 // Default to 0 when nulls exist
1750 v = ( v || 0 ).toString( 16 );
1751 return v.length === 1 ? "0" + v : v;
1754 toString: function() {
1755 return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
1758 color.fn.parse.prototype = color.fn;
1760 // Hsla conversions adapted from:
1761 // https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
1763 function hue2rgb( p, q, h ) {
1766 return p + ( q - p ) * h * 6;
1772 return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6;
1777 spaces.hsla.to = function( rgba ) {
1778 if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
1779 return [ null, null, null, rgba[ 3 ] ];
1781 var r = rgba[ 0 ] / 255,
1782 g = rgba[ 1 ] / 255,
1783 b = rgba[ 2 ] / 255,
1785 max = Math.max( r, g, b ),
1786 min = Math.min( r, g, b ),
1792 if ( min === max ) {
1794 } else if ( r === max ) {
1795 h = ( 60 * ( g - b ) / diff ) + 360;
1796 } else if ( g === max ) {
1797 h = ( 60 * ( b - r ) / diff ) + 120;
1799 h = ( 60 * ( r - g ) / diff ) + 240;
1802 // Chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
1803 // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
1806 } else if ( l <= 0.5 ) {
1809 s = diff / ( 2 - add );
1811 return [ Math.round( h ) % 360, s, l, a == null ? 1 : a ];
1814 spaces.hsla.from = function( hsla ) {
1815 if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
1816 return [ null, null, null, hsla[ 3 ] ];
1818 var h = hsla[ 0 ] / 360,
1822 q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
1826 Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
1827 Math.round( hue2rgb( p, q, h ) * 255 ),
1828 Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
1833 each( spaces, function( spaceName, space ) {
1834 var props = space.props,
1835 cache = space.cache,
1839 // Makes rgba() and hsla()
1840 color.fn[ spaceName ] = function( value ) {
1842 // Generate a cache for this space if it doesn't exist
1843 if ( to && !this[ cache ] ) {
1844 this[ cache ] = to( this._rgba );
1846 if ( value === undefined ) {
1847 return this[ cache ].slice();
1851 type = jQuery.type( value ),
1852 arr = ( type === "array" || type === "object" ) ? value : arguments,
1853 local = this[ cache ].slice();
1855 each( props, function( key, prop ) {
1856 var val = arr[ type === "object" ? key : prop.idx ];
1857 if ( val == null ) {
1858 val = local[ prop.idx ];
1860 local[ prop.idx ] = clamp( val, prop );
1864 ret = color( from( local ) );
1865 ret[ cache ] = local;
1868 return color( local );
1872 // Makes red() green() blue() alpha() hue() saturation() lightness()
1873 each( props, function( key, prop ) {
1875 // Alpha is included in more than one space
1876 if ( color.fn[ key ] ) {
1879 color.fn[ key ] = function( value ) {
1880 var vtype = jQuery.type( value ),
1881 fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
1882 local = this[ fn ](),
1883 cur = local[ prop.idx ],
1886 if ( vtype === "undefined" ) {
1890 if ( vtype === "function" ) {
1891 value = value.call( this, cur );
1892 vtype = jQuery.type( value );
1894 if ( value == null && prop.empty ) {
1897 if ( vtype === "string" ) {
1898 match = rplusequals.exec( value );
1900 value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
1903 local[ prop.idx ] = value;
1904 return this[ fn ]( local );
1909 // Add cssHook and .fx.step function for each named hook.
1910 // accept a space separated string of properties
1911 color.hook = function( hook ) {
1912 var hooks = hook.split( " " );
1913 each( hooks, function( i, hook ) {
1914 jQuery.cssHooks[ hook ] = {
1915 set: function( elem, value ) {
1916 var parsed, curElem,
1917 backgroundColor = "";
1919 if ( value !== "transparent" && ( jQuery.type( value ) !== "string" ||
1920 ( parsed = stringParse( value ) ) ) ) {
1921 value = color( parsed || value );
1922 if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
1923 curElem = hook === "backgroundColor" ? elem.parentNode : elem;
1925 ( backgroundColor === "" || backgroundColor === "transparent" ) &&
1926 curElem && curElem.style
1929 backgroundColor = jQuery.css( curElem, "backgroundColor" );
1930 curElem = curElem.parentNode;
1935 value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
1940 value = value.toRgbaString();
1943 elem.style[ hook ] = value;
1946 // Wrapped to prevent IE from throwing errors on "invalid" values like
1947 // 'auto' or 'inherit'
1951 jQuery.fx.step[ hook ] = function( fx ) {
1952 if ( !fx.colorInit ) {
1953 fx.start = color( fx.elem, hook );
1954 fx.end = color( fx.end );
1955 fx.colorInit = true;
1957 jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
1963 color.hook( stepHooks );
1965 jQuery.cssHooks.borderColor = {
1966 expand: function( value ) {
1969 each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
1970 expanded[ "border" + part + "Color" ] = value;
1976 // Basic color names only.
1977 // Usage of any of the other color names requires adding yourself or including
1978 // jquery.color.svg-names.js.
1979 colors = jQuery.Color.names = {
1981 // 4.1. Basic color keywords
1999 // 4.2.3. "transparent" color keyword
2000 transparent: [ null, null, null, 0 ],
2007 /******************************************************************************/
2008 /****************************** CLASS ANIMATIONS ******************************/
2009 /******************************************************************************/
2012 var classAnimationActions = [ "add", "remove", "toggle" ],
2026 [ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ],
2027 function( _, prop ) {
2028 $.fx.step[ prop ] = function( fx ) {
2029 if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
2030 jQuery.style( fx.elem, prop, fx.end );
2037 function getElementStyles( elem ) {
2039 style = elem.ownerDocument.defaultView ?
2040 elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :
2044 if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
2048 if ( typeof style[ key ] === "string" ) {
2049 styles[ $.camelCase( key ) ] = style[ key ];
2053 // Support: Opera, IE <9
2055 for ( key in style ) {
2056 if ( typeof style[ key ] === "string" ) {
2057 styles[ key ] = style[ key ];
2065 function styleDifference( oldStyle, newStyle ) {
2069 for ( name in newStyle ) {
2070 value = newStyle[ name ];
2071 if ( oldStyle[ name ] !== value ) {
2072 if ( !shorthandStyles[ name ] ) {
2073 if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
2074 diff[ name ] = value;
2083 // Support: jQuery <1.8
2084 if ( !$.fn.addBack ) {
2085 $.fn.addBack = function( selector ) {
2086 return this.add( selector == null ?
2087 this.prevObject : this.prevObject.filter( selector )
2092 $.effects.animateClass = function( value, duration, easing, callback ) {
2093 var o = $.speed( duration, easing, callback );
2095 return this.queue( function() {
2096 var animated = $( this ),
2097 baseClass = animated.attr( "class" ) || "",
2099 allAnimations = o.children ? animated.find( "*" ).addBack() : animated;
2101 // Map the animated objects to store the original styles.
2102 allAnimations = allAnimations.map( function() {
2106 start: getElementStyles( this )
2110 // Apply class change
2111 applyClassChange = function() {
2112 $.each( classAnimationActions, function( i, action ) {
2113 if ( value[ action ] ) {
2114 animated[ action + "Class" ]( value[ action ] );
2120 // Map all animated objects again - calculate new styles and diff
2121 allAnimations = allAnimations.map( function() {
2122 this.end = getElementStyles( this.el[ 0 ] );
2123 this.diff = styleDifference( this.start, this.end );
2127 // Apply original class
2128 animated.attr( "class", baseClass );
2130 // Map all animated objects again - this time collecting a promise
2131 allAnimations = allAnimations.map( function() {
2132 var styleInfo = this,
2134 opts = $.extend( {}, o, {
2136 complete: function() {
2137 dfd.resolve( styleInfo );
2141 this.el.animate( this.diff, opts );
2142 return dfd.promise();
2145 // Once all animations have completed:
2146 $.when.apply( $, allAnimations.get() ).done( function() {
2148 // Set the final class
2151 // For each animated element,
2152 // clear all css properties that were animated
2153 $.each( arguments, function() {
2155 $.each( this.diff, function( key ) {
2160 // This is guarnteed to be there if you use jQuery.speed()
2161 // it also handles dequeuing the next anim...
2162 o.complete.call( animated[ 0 ] );
2168 addClass: ( function( orig ) {
2169 return function( classNames, speed, easing, callback ) {
2171 $.effects.animateClass.call( this,
2172 { add: classNames }, speed, easing, callback ) :
2173 orig.apply( this, arguments );
2175 } )( $.fn.addClass ),
2177 removeClass: ( function( orig ) {
2178 return function( classNames, speed, easing, callback ) {
2179 return arguments.length > 1 ?
2180 $.effects.animateClass.call( this,
2181 { remove: classNames }, speed, easing, callback ) :
2182 orig.apply( this, arguments );
2184 } )( $.fn.removeClass ),
2186 toggleClass: ( function( orig ) {
2187 return function( classNames, force, speed, easing, callback ) {
2188 if ( typeof force === "boolean" || force === undefined ) {
2191 // Without speed parameter
2192 return orig.apply( this, arguments );
2194 return $.effects.animateClass.call( this,
2195 ( force ? { add: classNames } : { remove: classNames } ),
2196 speed, easing, callback );
2200 // Without force parameter
2201 return $.effects.animateClass.call( this,
2202 { toggle: classNames }, force, speed, easing );
2205 } )( $.fn.toggleClass ),
2207 switchClass: function( remove, add, speed, easing, callback ) {
2208 return $.effects.animateClass.call( this, {
2211 }, speed, easing, callback );
2217 /******************************************************************************/
2218 /*********************************** EFFECTS **********************************/
2219 /******************************************************************************/
2223 if ( $.expr && $.expr.filters && $.expr.filters.animated ) {
2224 $.expr.filters.animated = ( function( orig ) {
2225 return function( elem ) {
2226 return !!$( elem ).data( dataSpaceAnimated ) || orig( elem );
2228 } )( $.expr.filters.animated );
2231 if ( $.uiBackCompat !== false ) {
2232 $.extend( $.effects, {
2234 // Saves a set of properties in a data storage
2235 save: function( element, set ) {
2236 var i = 0, length = set.length;
2237 for ( ; i < length; i++ ) {
2238 if ( set[ i ] !== null ) {
2239 element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
2244 // Restores a set of previously saved properties from a data storage
2245 restore: function( element, set ) {
2246 var val, i = 0, length = set.length;
2247 for ( ; i < length; i++ ) {
2248 if ( set[ i ] !== null ) {
2249 val = element.data( dataSpace + set[ i ] );
2250 element.css( set[ i ], val );
2255 setMode: function( el, mode ) {
2256 if ( mode === "toggle" ) {
2257 mode = el.is( ":hidden" ) ? "show" : "hide";
2262 // Wraps the element around a wrapper that copies position properties
2263 createWrapper: function( element ) {
2265 // If the element is already wrapped, return it
2266 if ( element.parent().is( ".ui-effects-wrapper" ) ) {
2267 return element.parent();
2272 width: element.outerWidth( true ),
2273 height: element.outerHeight( true ),
2274 "float": element.css( "float" )
2276 wrapper = $( "<div></div>" )
2277 .addClass( "ui-effects-wrapper" )
2280 background: "transparent",
2286 // Store the size in case width/height are defined in % - Fixes #5245
2288 width: element.width(),
2289 height: element.height()
2291 active = document.activeElement;
2294 // Firefox incorrectly exposes anonymous content
2295 // https://bugzilla.mozilla.org/show_bug.cgi?id=561664
2299 active = document.body;
2302 element.wrap( wrapper );
2304 // Fixes #7595 - Elements lose focus when wrapped.
2305 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
2306 $( active ).trigger( "focus" );
2309 // Hotfix for jQuery 1.4 since some change in wrap() seems to actually
2310 // lose the reference to the wrapped element
2311 wrapper = element.parent();
2313 // Transfer positioning properties to the wrapper
2314 if ( element.css( "position" ) === "static" ) {
2315 wrapper.css( { position: "relative" } );
2316 element.css( { position: "relative" } );
2319 position: element.css( "position" ),
2320 zIndex: element.css( "z-index" )
2322 $.each( [ "top", "left", "bottom", "right" ], function( i, pos ) {
2323 props[ pos ] = element.css( pos );
2324 if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
2325 props[ pos ] = "auto";
2329 position: "relative",
2336 element.css( size );
2338 return wrapper.css( props ).show();
2341 removeWrapper: function( element ) {
2342 var active = document.activeElement;
2344 if ( element.parent().is( ".ui-effects-wrapper" ) ) {
2345 element.parent().replaceWith( element );
2347 // Fixes #7595 - Elements lose focus when wrapped.
2348 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
2349 $( active ).trigger( "focus" );
2358 $.extend( $.effects, {
2361 define: function( name, mode, effect ) {
2367 $.effects.effect[ name ] = effect;
2368 $.effects.effect[ name ].mode = mode;
2373 scaledDimensions: function( element, percent, direction ) {
2374 if ( percent === 0 ) {
2383 var x = direction !== "horizontal" ? ( ( percent || 100 ) / 100 ) : 1,
2384 y = direction !== "vertical" ? ( ( percent || 100 ) / 100 ) : 1;
2387 height: element.height() * y,
2388 width: element.width() * x,
2389 outerHeight: element.outerHeight() * y,
2390 outerWidth: element.outerWidth() * x
2395 clipToBox: function( animation ) {
2397 width: animation.clip.right - animation.clip.left,
2398 height: animation.clip.bottom - animation.clip.top,
2399 left: animation.clip.left,
2400 top: animation.clip.top
2404 // Injects recently queued functions to be first in line (after "inprogress")
2405 unshift: function( element, queueLength, count ) {
2406 var queue = element.queue();
2408 if ( queueLength > 1 ) {
2409 queue.splice.apply( queue,
2410 [ 1, 0 ].concat( queue.splice( queueLength, count ) ) );
2415 saveStyle: function( element ) {
2416 element.data( dataSpaceStyle, element[ 0 ].style.cssText );
2419 restoreStyle: function( element ) {
2420 element[ 0 ].style.cssText = element.data( dataSpaceStyle ) || "";
2421 element.removeData( dataSpaceStyle );
2424 mode: function( element, mode ) {
2425 var hidden = element.is( ":hidden" );
2427 if ( mode === "toggle" ) {
2428 mode = hidden ? "show" : "hide";
2430 if ( hidden ? mode === "hide" : mode === "show" ) {
2436 // Translates a [top,left] array into a baseline value
2437 getBaseline: function( origin, original ) {
2440 switch ( origin[ 0 ] ) {
2451 y = origin[ 0 ] / original.height;
2454 switch ( origin[ 1 ] ) {
2465 x = origin[ 1 ] / original.width;
2474 // Creates a placeholder element so that the original element can be made absolute
2475 createPlaceholder: function( element ) {
2477 cssPosition = element.css( "position" ),
2478 position = element.position();
2480 // Lock in margins first to account for form elements, which
2481 // will change margin if you explicitly set height
2482 // see: http://jsfiddle.net/JZSMt/3/ https://bugs.webkit.org/show_bug.cgi?id=107380
2485 marginTop: element.css( "marginTop" ),
2486 marginBottom: element.css( "marginBottom" ),
2487 marginLeft: element.css( "marginLeft" ),
2488 marginRight: element.css( "marginRight" )
2490 .outerWidth( element.outerWidth() )
2491 .outerHeight( element.outerHeight() );
2493 if ( /^(static|relative)/.test( cssPosition ) ) {
2494 cssPosition = "absolute";
2496 placeholder = $( "<" + element[ 0 ].nodeName + ">" ).insertAfter( element ).css( {
2498 // Convert inline to inline block to account for inline elements
2499 // that turn to inline block based on content (like img)
2500 display: /^(inline|ruby)/.test( element.css( "display" ) ) ?
2503 visibility: "hidden",
2505 // Margins need to be set to account for margin collapse
2506 marginTop: element.css( "marginTop" ),
2507 marginBottom: element.css( "marginBottom" ),
2508 marginLeft: element.css( "marginLeft" ),
2509 marginRight: element.css( "marginRight" ),
2510 "float": element.css( "float" )
2512 .outerWidth( element.outerWidth() )
2513 .outerHeight( element.outerHeight() )
2514 .addClass( "ui-effects-placeholder" );
2516 element.data( dataSpace + "placeholder", placeholder );
2520 position: cssPosition,
2521 left: position.left,
2528 removePlaceholder: function( element ) {
2529 var dataKey = dataSpace + "placeholder",
2530 placeholder = element.data( dataKey );
2532 if ( placeholder ) {
2533 placeholder.remove();
2534 element.removeData( dataKey );
2538 // Removes a placeholder if it exists and restores
2539 // properties that were modified during placeholder creation
2540 cleanUp: function( element ) {
2541 $.effects.restoreStyle( element );
2542 $.effects.removePlaceholder( element );
2545 setTransition: function( element, list, factor, value ) {
2546 value = value || {};
2547 $.each( list, function( i, x ) {
2548 var unit = element.cssUnit( x );
2549 if ( unit[ 0 ] > 0 ) {
2550 value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
2557 // Return an effect options object for the given parameters:
2558 function _normalizeArguments( effect, options, speed, callback ) {
2560 // Allow passing all options as the first parameter
2561 if ( $.isPlainObject( effect ) ) {
2563 effect = effect.effect;
2566 // Convert to an object
2567 effect = { effect: effect };
2569 // Catch (effect, null, ...)
2570 if ( options == null ) {
2574 // Catch (effect, callback)
2575 if ( $.isFunction( options ) ) {
2581 // Catch (effect, speed, ?)
2582 if ( typeof options === "number" || $.fx.speeds[ options ] ) {
2588 // Catch (effect, options, callback)
2589 if ( $.isFunction( speed ) ) {
2594 // Add options to effect
2596 $.extend( effect, options );
2599 speed = speed || options.duration;
2600 effect.duration = $.fx.off ? 0 :
2601 typeof speed === "number" ? speed :
2602 speed in $.fx.speeds ? $.fx.speeds[ speed ] :
2603 $.fx.speeds._default;
2605 effect.complete = callback || options.complete;
2610 function standardAnimationOption( option ) {
2612 // Valid standard speeds (nothing, number, named speed)
2613 if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) {
2617 // Invalid strings - treat as "normal" speed
2618 if ( typeof option === "string" && !$.effects.effect[ option ] ) {
2622 // Complete callback
2623 if ( $.isFunction( option ) ) {
2627 // Options hash (but not naming an effect)
2628 if ( typeof option === "object" && !option.effect ) {
2632 // Didn't match any standard API
2637 effect: function( /* effect, options, speed, callback */ ) {
2638 var args = _normalizeArguments.apply( this, arguments ),
2639 effectMethod = $.effects.effect[ args.effect ],
2640 defaultMode = effectMethod.mode,
2642 queueName = queue || "fx",
2643 complete = args.complete,
2646 prefilter = function( next ) {
2648 normalizedMode = $.effects.mode( el, mode ) || defaultMode;
2650 // Sentinel for duck-punching the :animated psuedo-selector
2651 el.data( dataSpaceAnimated, true );
2653 // Save effect mode for later use,
2654 // we can't just call $.effects.mode again later,
2655 // as the .show() below destroys the initial state
2656 modes.push( normalizedMode );
2658 // See $.uiBackCompat inside of run() for removal of defaultMode in 1.13
2659 if ( defaultMode && ( normalizedMode === "show" ||
2660 ( normalizedMode === defaultMode && normalizedMode === "hide" ) ) ) {
2664 if ( !defaultMode || normalizedMode !== "none" ) {
2665 $.effects.saveStyle( el );
2668 if ( $.isFunction( next ) ) {
2673 if ( $.fx.off || !effectMethod ) {
2675 // Delegate to the original method (e.g., .show()) if possible
2677 return this[ mode ]( args.duration, complete );
2679 return this.each( function() {
2681 complete.call( this );
2687 function run( next ) {
2688 var elem = $( this );
2690 function cleanup() {
2691 elem.removeData( dataSpaceAnimated );
2693 $.effects.cleanUp( elem );
2695 if ( args.mode === "hide" ) {
2703 if ( $.isFunction( complete ) ) {
2704 complete.call( elem[ 0 ] );
2707 if ( $.isFunction( next ) ) {
2712 // Override mode option on a per element basis,
2713 // as toggle can be either show or hide depending on element state
2714 args.mode = modes.shift();
2716 if ( $.uiBackCompat !== false && !defaultMode ) {
2717 if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
2719 // Call the core method to track "olddisplay" properly
2723 effectMethod.call( elem[ 0 ], args, done );
2726 if ( args.mode === "none" ) {
2728 // Call the core method to track "olddisplay" properly
2732 effectMethod.call( elem[ 0 ], args, cleanup );
2737 // Run prefilter on all elements first to ensure that
2738 // any showing or hiding happens before placeholder creation,
2739 // which ensures that any layout changes are correctly captured.
2740 return queue === false ?
2741 this.each( prefilter ).each( run ) :
2742 this.queue( queueName, prefilter ).queue( queueName, run );
2745 show: ( function( orig ) {
2746 return function( option ) {
2747 if ( standardAnimationOption( option ) ) {
2748 return orig.apply( this, arguments );
2750 var args = _normalizeArguments.apply( this, arguments );
2752 return this.effect.call( this, args );
2757 hide: ( function( orig ) {
2758 return function( option ) {
2759 if ( standardAnimationOption( option ) ) {
2760 return orig.apply( this, arguments );
2762 var args = _normalizeArguments.apply( this, arguments );
2764 return this.effect.call( this, args );
2769 toggle: ( function( orig ) {
2770 return function( option ) {
2771 if ( standardAnimationOption( option ) || typeof option === "boolean" ) {
2772 return orig.apply( this, arguments );
2774 var args = _normalizeArguments.apply( this, arguments );
2775 args.mode = "toggle";
2776 return this.effect.call( this, args );
2781 cssUnit: function( key ) {
2782 var style = this.css( key ),
2785 $.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
2786 if ( style.indexOf( unit ) > 0 ) {
2787 val = [ parseFloat( style ), unit ];
2793 cssClip: function( clipObj ) {
2795 return this.css( "clip", "rect(" + clipObj.top + "px " + clipObj.right + "px " +
2796 clipObj.bottom + "px " + clipObj.left + "px)" );
2798 return parseClip( this.css( "clip" ), this );
2801 transfer: function( options, done ) {
2802 var element = $( this ),
2803 target = $( options.to ),
2804 targetFixed = target.css( "position" ) === "fixed",
2806 fixTop = targetFixed ? body.scrollTop() : 0,
2807 fixLeft = targetFixed ? body.scrollLeft() : 0,
2808 endPosition = target.offset(),
2810 top: endPosition.top - fixTop,
2811 left: endPosition.left - fixLeft,
2812 height: target.innerHeight(),
2813 width: target.innerWidth()
2815 startPosition = element.offset(),
2816 transfer = $( "<div class='ui-effects-transfer'></div>" )
2818 .addClass( options.className )
2820 top: startPosition.top - fixTop,
2821 left: startPosition.left - fixLeft,
2822 height: element.innerHeight(),
2823 width: element.innerWidth(),
2824 position: targetFixed ? "fixed" : "absolute"
2826 .animate( animation, options.duration, options.easing, function() {
2828 if ( $.isFunction( done ) ) {
2835 function parseClip( str, element ) {
2836 var outerWidth = element.outerWidth(),
2837 outerHeight = element.outerHeight(),
2838 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)\)$/,
2839 values = clipRegex.exec( str ) || [ "", 0, outerWidth, outerHeight, 0 ];
2842 top: parseFloat( values[ 1 ] ) || 0,
2843 right: values[ 2 ] === "auto" ? outerWidth : parseFloat( values[ 2 ] ),
2844 bottom: values[ 3 ] === "auto" ? outerHeight : parseFloat( values[ 3 ] ),
2845 left: parseFloat( values[ 4 ] ) || 0
2849 $.fx.step.clip = function( fx ) {
2850 if ( !fx.clipInit ) {
2851 fx.start = $( fx.elem ).cssClip();
2852 if ( typeof fx.end === "string" ) {
2853 fx.end = parseClip( fx.end, fx.elem );
2858 $( fx.elem ).cssClip( {
2859 top: fx.pos * ( fx.end.top - fx.start.top ) + fx.start.top,
2860 right: fx.pos * ( fx.end.right - fx.start.right ) + fx.start.right,
2861 bottom: fx.pos * ( fx.end.bottom - fx.start.bottom ) + fx.start.bottom,
2862 left: fx.pos * ( fx.end.left - fx.start.left ) + fx.start.left
2868 /******************************************************************************/
2869 /*********************************** EASING ***********************************/
2870 /******************************************************************************/
2874 // Based on easing equations from Robert Penner (http://www.robertpenner.com/easing)
2876 var baseEasings = {};
2878 $.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
2879 baseEasings[ name ] = function( p ) {
2880 return Math.pow( p, i + 2 );
2884 $.extend( baseEasings, {
2885 Sine: function( p ) {
2886 return 1 - Math.cos( p * Math.PI / 2 );
2888 Circ: function( p ) {
2889 return 1 - Math.sqrt( 1 - p * p );
2891 Elastic: function( p ) {
2892 return p === 0 || p === 1 ? p :
2893 -Math.pow( 2, 8 * ( p - 1 ) ) * Math.sin( ( ( p - 1 ) * 80 - 7.5 ) * Math.PI / 15 );
2895 Back: function( p ) {
2896 return p * p * ( 3 * p - 2 );
2898 Bounce: function( p ) {
2902 while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
2903 return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
2907 $.each( baseEasings, function( name, easeIn ) {
2908 $.easing[ "easeIn" + name ] = easeIn;
2909 $.easing[ "easeOut" + name ] = function( p ) {
2910 return 1 - easeIn( 1 - p );
2912 $.easing[ "easeInOut" + name ] = function( p ) {
2914 easeIn( p * 2 ) / 2 :
2915 1 - easeIn( p * -2 + 2 ) / 2;
2921 var effect = $.effects;
2925 * jQuery UI Effects Blind 1.12.1
2926 * http://jqueryui.com
2928 * Copyright jQuery Foundation and other contributors
2929 * Released under the MIT license.
2930 * http://jquery.org/license
2933 //>>label: Blind Effect
2935 //>>description: Blinds the element.
2936 //>>docs: http://api.jqueryui.com/blind-effect/
2937 //>>demos: http://jqueryui.com/effect/
2941 var effectsEffectBlind = $.effects.define( "blind", "hide", function( options, done ) {
2943 up: [ "bottom", "top" ],
2944 vertical: [ "bottom", "top" ],
2945 down: [ "top", "bottom" ],
2946 left: [ "right", "left" ],
2947 horizontal: [ "right", "left" ],
2948 right: [ "left", "right" ]
2950 element = $( this ),
2951 direction = options.direction || "up",
2952 start = element.cssClip(),
2953 animate = { clip: $.extend( {}, start ) },
2954 placeholder = $.effects.createPlaceholder( element );
2956 animate.clip[ map[ direction ][ 0 ] ] = animate.clip[ map[ direction ][ 1 ] ];
2958 if ( options.mode === "show" ) {
2959 element.cssClip( animate.clip );
2960 if ( placeholder ) {
2961 placeholder.css( $.effects.clipToBox( animate ) );
2964 animate.clip = start;
2967 if ( placeholder ) {
2968 placeholder.animate( $.effects.clipToBox( animate ), options.duration, options.easing );
2971 element.animate( animate, {
2973 duration: options.duration,
2974 easing: options.easing,
2981 * jQuery UI Effects Bounce 1.12.1
2982 * http://jqueryui.com
2984 * Copyright jQuery Foundation and other contributors
2985 * Released under the MIT license.
2986 * http://jquery.org/license
2989 //>>label: Bounce Effect
2991 //>>description: Bounces an element horizontally or vertically n times.
2992 //>>docs: http://api.jqueryui.com/bounce-effect/
2993 //>>demos: http://jqueryui.com/effect/
2997 var effectsEffectBounce = $.effects.define( "bounce", function( options, done ) {
2998 var upAnim, downAnim, refValue,
2999 element = $( this ),
3002 mode = options.mode,
3003 hide = mode === "hide",
3004 show = mode === "show",
3005 direction = options.direction || "up",
3006 distance = options.distance,
3007 times = options.times || 5,
3009 // Number of internal animations
3010 anims = times * 2 + ( show || hide ? 1 : 0 ),
3011 speed = options.duration / anims,
3012 easing = options.easing,
3015 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
3016 motion = ( direction === "up" || direction === "left" ),
3019 queuelen = element.queue().length;
3021 $.effects.createPlaceholder( element );
3023 refValue = element.css( ref );
3025 // Default distance for the BIGGEST bounce is the outer Distance / 3
3027 distance = element[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
3031 downAnim = { opacity: 1 };
3032 downAnim[ ref ] = refValue;
3034 // If we are showing, force opacity 0 and set the initial position
3035 // then do the "first" animation
3037 .css( "opacity", 0 )
3038 .css( ref, motion ? -distance * 2 : distance * 2 )
3039 .animate( downAnim, speed, easing );
3042 // Start at the smallest distance if we are hiding
3044 distance = distance / Math.pow( 2, times - 1 );
3048 downAnim[ ref ] = refValue;
3050 // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
3051 for ( ; i < times; i++ ) {
3053 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
3056 .animate( upAnim, speed, easing )
3057 .animate( downAnim, speed, easing );
3059 distance = hide ? distance * 2 : distance / 2;
3062 // Last Bounce when Hiding
3064 upAnim = { opacity: 0 };
3065 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
3067 element.animate( upAnim, speed, easing );
3070 element.queue( done );
3072 $.effects.unshift( element, queuelen, anims + 1 );
3077 * jQuery UI Effects Clip 1.12.1
3078 * http://jqueryui.com
3080 * Copyright jQuery Foundation and other contributors
3081 * Released under the MIT license.
3082 * http://jquery.org/license
3085 //>>label: Clip Effect
3087 //>>description: Clips the element on and off like an old TV.
3088 //>>docs: http://api.jqueryui.com/clip-effect/
3089 //>>demos: http://jqueryui.com/effect/
3093 var effectsEffectClip = $.effects.define( "clip", "hide", function( options, done ) {
3096 element = $( this ),
3097 direction = options.direction || "vertical",
3098 both = direction === "both",
3099 horizontal = both || direction === "horizontal",
3100 vertical = both || direction === "vertical";
3102 start = element.cssClip();
3104 top: vertical ? ( start.bottom - start.top ) / 2 : start.top,
3105 right: horizontal ? ( start.right - start.left ) / 2 : start.right,
3106 bottom: vertical ? ( start.bottom - start.top ) / 2 : start.bottom,
3107 left: horizontal ? ( start.right - start.left ) / 2 : start.left
3110 $.effects.createPlaceholder( element );
3112 if ( options.mode === "show" ) {
3113 element.cssClip( animate.clip );
3114 animate.clip = start;
3117 element.animate( animate, {
3119 duration: options.duration,
3120 easing: options.easing,
3128 * jQuery UI Effects Drop 1.12.1
3129 * http://jqueryui.com
3131 * Copyright jQuery Foundation and other contributors
3132 * Released under the MIT license.
3133 * http://jquery.org/license
3136 //>>label: Drop Effect
3138 //>>description: Moves an element in one direction and hides it at the same time.
3139 //>>docs: http://api.jqueryui.com/drop-effect/
3140 //>>demos: http://jqueryui.com/effect/
3144 var effectsEffectDrop = $.effects.define( "drop", "hide", function( options, done ) {
3147 element = $( this ),
3148 mode = options.mode,
3149 show = mode === "show",
3150 direction = options.direction || "left",
3151 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
3152 motion = ( direction === "up" || direction === "left" ) ? "-=" : "+=",
3153 oppositeMotion = ( motion === "+=" ) ? "-=" : "+=",
3158 $.effects.createPlaceholder( element );
3160 distance = options.distance ||
3161 element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ) / 2;
3163 animation[ ref ] = motion + distance;
3166 element.css( animation );
3168 animation[ ref ] = oppositeMotion + distance;
3169 animation.opacity = 1;
3173 element.animate( animation, {
3175 duration: options.duration,
3176 easing: options.easing,
3183 * jQuery UI Effects Explode 1.12.1
3184 * http://jqueryui.com
3186 * Copyright jQuery Foundation and other contributors
3187 * Released under the MIT license.
3188 * http://jquery.org/license
3191 //>>label: Explode Effect
3193 // jscs:disable maximumLineLength
3194 //>>description: Explodes an element in all directions into n pieces. Implodes an element to its original wholeness.
3195 // jscs:enable maximumLineLength
3196 //>>docs: http://api.jqueryui.com/explode-effect/
3197 //>>demos: http://jqueryui.com/effect/
3201 var effectsEffectExplode = $.effects.define( "explode", "hide", function( options, done ) {
3203 var i, j, left, top, mx, my,
3204 rows = options.pieces ? Math.round( Math.sqrt( options.pieces ) ) : 3,
3206 element = $( this ),
3207 mode = options.mode,
3208 show = mode === "show",
3210 // Show and then visibility:hidden the element before calculating offset
3211 offset = element.show().css( "visibility", "hidden" ).offset(),
3213 // Width and height of a piece
3214 width = Math.ceil( element.outerWidth() / cells ),
3215 height = Math.ceil( element.outerHeight() / rows ),
3218 // Children animate complete:
3219 function childComplete() {
3220 pieces.push( this );
3221 if ( pieces.length === rows * cells ) {
3226 // Clone the element for each row and cell.
3227 for ( i = 0; i < rows; i++ ) { // ===>
3228 top = offset.top + i * height;
3229 my = i - ( rows - 1 ) / 2;
3231 for ( j = 0; j < cells; j++ ) { // |||
3232 left = offset.left + j * width;
3233 mx = j - ( cells - 1 ) / 2;
3235 // Create a clone of the now hidden main element that will be absolute positioned
3236 // within a wrapper div off the -left and -top equal to size of our pieces
3240 .wrap( "<div></div>" )
3242 position: "absolute",
3243 visibility: "visible",
3248 // Select the wrapper - make it overflow: hidden and absolute positioned based on
3249 // where the original was located +left and +top equal to the size of pieces
3251 .addClass( "ui-effects-explode" )
3253 position: "absolute",
3257 left: left + ( show ? mx * width : 0 ),
3258 top: top + ( show ? my * height : 0 ),
3259 opacity: show ? 0 : 1
3262 left: left + ( show ? 0 : mx * width ),
3263 top: top + ( show ? 0 : my * height ),
3264 opacity: show ? 1 : 0
3265 }, options.duration || 500, options.easing, childComplete );
3269 function animComplete() {
3271 visibility: "visible"
3273 $( pieces ).remove();
3280 * jQuery UI Effects Fade 1.12.1
3281 * http://jqueryui.com
3283 * Copyright jQuery Foundation and other contributors
3284 * Released under the MIT license.
3285 * http://jquery.org/license
3288 //>>label: Fade Effect
3290 //>>description: Fades the element.
3291 //>>docs: http://api.jqueryui.com/fade-effect/
3292 //>>demos: http://jqueryui.com/effect/
3296 var effectsEffectFade = $.effects.define( "fade", "toggle", function( options, done ) {
3297 var show = options.mode === "show";
3300 .css( "opacity", show ? 0 : 1 )
3302 opacity: show ? 1 : 0
3305 duration: options.duration,
3306 easing: options.easing,
3313 * jQuery UI Effects Fold 1.12.1
3314 * http://jqueryui.com
3316 * Copyright jQuery Foundation and other contributors
3317 * Released under the MIT license.
3318 * http://jquery.org/license
3321 //>>label: Fold Effect
3323 //>>description: Folds an element first horizontally and then vertically.
3324 //>>docs: http://api.jqueryui.com/fold-effect/
3325 //>>demos: http://jqueryui.com/effect/
3329 var effectsEffectFold = $.effects.define( "fold", "hide", function( options, done ) {
3332 var element = $( this ),
3333 mode = options.mode,
3334 show = mode === "show",
3335 hide = mode === "hide",
3336 size = options.size || 15,
3337 percent = /([0-9]+)%/.exec( size ),
3338 horizFirst = !!options.horizFirst,
3339 ref = horizFirst ? [ "right", "bottom" ] : [ "bottom", "right" ],
3340 duration = options.duration / 2,
3342 placeholder = $.effects.createPlaceholder( element ),
3344 start = element.cssClip(),
3345 animation1 = { clip: $.extend( {}, start ) },
3346 animation2 = { clip: $.extend( {}, start ) },
3348 distance = [ start[ ref[ 0 ] ], start[ ref[ 1 ] ] ],
3350 queuelen = element.queue().length;
3353 size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
3355 animation1.clip[ ref[ 0 ] ] = size;
3356 animation2.clip[ ref[ 0 ] ] = size;
3357 animation2.clip[ ref[ 1 ] ] = 0;
3360 element.cssClip( animation2.clip );
3361 if ( placeholder ) {
3362 placeholder.css( $.effects.clipToBox( animation2 ) );
3365 animation2.clip = start;
3370 .queue( function( next ) {
3371 if ( placeholder ) {
3373 .animate( $.effects.clipToBox( animation1 ), duration, options.easing )
3374 .animate( $.effects.clipToBox( animation2 ), duration, options.easing );
3379 .animate( animation1, duration, options.easing )
3380 .animate( animation2, duration, options.easing )
3383 $.effects.unshift( element, queuelen, 4 );
3388 * jQuery UI Effects Highlight 1.12.1
3389 * http://jqueryui.com
3391 * Copyright jQuery Foundation and other contributors
3392 * Released under the MIT license.
3393 * http://jquery.org/license
3396 //>>label: Highlight Effect
3398 //>>description: Highlights the background of an element in a defined color for a custom duration.
3399 //>>docs: http://api.jqueryui.com/highlight-effect/
3400 //>>demos: http://jqueryui.com/effect/
3404 var effectsEffectHighlight = $.effects.define( "highlight", "show", function( options, done ) {
3405 var element = $( this ),
3407 backgroundColor: element.css( "backgroundColor" )
3410 if ( options.mode === "hide" ) {
3411 animation.opacity = 0;
3414 $.effects.saveStyle( element );
3418 backgroundImage: "none",
3419 backgroundColor: options.color || "#ffff99"
3421 .animate( animation, {
3423 duration: options.duration,
3424 easing: options.easing,
3431 * jQuery UI Effects Size 1.12.1
3432 * http://jqueryui.com
3434 * Copyright jQuery Foundation and other contributors
3435 * Released under the MIT license.
3436 * http://jquery.org/license
3439 //>>label: Size Effect
3441 //>>description: Resize an element to a specified width and height.
3442 //>>docs: http://api.jqueryui.com/size-effect/
3443 //>>demos: http://jqueryui.com/effect/
3447 var effectsEffectSize = $.effects.define( "size", function( options, done ) {
3450 var baseline, factor, temp,
3451 element = $( this ),
3453 // Copy for children
3454 cProps = [ "fontSize" ],
3455 vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
3456 hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],
3459 mode = options.mode,
3460 restore = mode !== "effect",
3461 scale = options.scale || "both",
3462 origin = options.origin || [ "middle", "center" ],
3463 position = element.css( "position" ),
3464 pos = element.position(),
3465 original = $.effects.scaledDimensions( element ),
3466 from = options.from || original,
3467 to = options.to || $.effects.scaledDimensions( element, 0 );
3469 $.effects.createPlaceholder( element );
3471 if ( mode === "show" ) {
3477 // Set scaling factor
3480 y: from.height / original.height,
3481 x: from.width / original.width
3484 y: to.height / original.height,
3485 x: to.width / original.width
3489 // Scale the css box
3490 if ( scale === "box" || scale === "both" ) {
3492 // Vertical props scaling
3493 if ( factor.from.y !== factor.to.y ) {
3494 from = $.effects.setTransition( element, vProps, factor.from.y, from );
3495 to = $.effects.setTransition( element, vProps, factor.to.y, to );
3498 // Horizontal props scaling
3499 if ( factor.from.x !== factor.to.x ) {
3500 from = $.effects.setTransition( element, hProps, factor.from.x, from );
3501 to = $.effects.setTransition( element, hProps, factor.to.x, to );
3505 // Scale the content
3506 if ( scale === "content" || scale === "both" ) {
3508 // Vertical props scaling
3509 if ( factor.from.y !== factor.to.y ) {
3510 from = $.effects.setTransition( element, cProps, factor.from.y, from );
3511 to = $.effects.setTransition( element, cProps, factor.to.y, to );
3515 // Adjust the position properties based on the provided origin points
3517 baseline = $.effects.getBaseline( origin, original );
3518 from.top = ( original.outerHeight - from.outerHeight ) * baseline.y + pos.top;
3519 from.left = ( original.outerWidth - from.outerWidth ) * baseline.x + pos.left;
3520 to.top = ( original.outerHeight - to.outerHeight ) * baseline.y + pos.top;
3521 to.left = ( original.outerWidth - to.outerWidth ) * baseline.x + pos.left;
3523 element.css( from );
3525 // Animate the children if desired
3526 if ( scale === "content" || scale === "both" ) {
3528 vProps = vProps.concat( [ "marginTop", "marginBottom" ] ).concat( cProps );
3529 hProps = hProps.concat( [ "marginLeft", "marginRight" ] );
3531 // Only animate children with width attributes specified
3532 // TODO: is this right? should we include anything with css width specified as well
3533 element.find( "*[width]" ).each( function() {
3534 var child = $( this ),
3535 childOriginal = $.effects.scaledDimensions( child ),
3537 height: childOriginal.height * factor.from.y,
3538 width: childOriginal.width * factor.from.x,
3539 outerHeight: childOriginal.outerHeight * factor.from.y,
3540 outerWidth: childOriginal.outerWidth * factor.from.x
3543 height: childOriginal.height * factor.to.y,
3544 width: childOriginal.width * factor.to.x,
3545 outerHeight: childOriginal.height * factor.to.y,
3546 outerWidth: childOriginal.width * factor.to.x
3549 // Vertical props scaling
3550 if ( factor.from.y !== factor.to.y ) {
3551 childFrom = $.effects.setTransition( child, vProps, factor.from.y, childFrom );
3552 childTo = $.effects.setTransition( child, vProps, factor.to.y, childTo );
3555 // Horizontal props scaling
3556 if ( factor.from.x !== factor.to.x ) {
3557 childFrom = $.effects.setTransition( child, hProps, factor.from.x, childFrom );
3558 childTo = $.effects.setTransition( child, hProps, factor.to.x, childTo );
3562 $.effects.saveStyle( child );
3566 child.css( childFrom );
3567 child.animate( childTo, options.duration, options.easing, function() {
3571 $.effects.restoreStyle( child );
3578 element.animate( to, {
3580 duration: options.duration,
3581 easing: options.easing,
3582 complete: function() {
3584 var offset = element.offset();
3586 if ( to.opacity === 0 ) {
3587 element.css( "opacity", from.opacity );
3592 .css( "position", position === "static" ? "relative" : position )
3595 // Need to save style here so that automatic style restoration
3596 // doesn't restore to the original styles from before the animation.
3597 $.effects.saveStyle( element );
3608 * jQuery UI Effects Scale 1.12.1
3609 * http://jqueryui.com
3611 * Copyright jQuery Foundation and other contributors
3612 * Released under the MIT license.
3613 * http://jquery.org/license
3616 //>>label: Scale Effect
3618 //>>description: Grows or shrinks an element and its content.
3619 //>>docs: http://api.jqueryui.com/scale-effect/
3620 //>>demos: http://jqueryui.com/effect/
3624 var effectsEffectScale = $.effects.define( "scale", function( options, done ) {
3628 mode = options.mode,
3629 percent = parseInt( options.percent, 10 ) ||
3630 ( parseInt( options.percent, 10 ) === 0 ? 0 : ( mode !== "effect" ? 0 : 100 ) ),
3632 newOptions = $.extend( true, {
3633 from: $.effects.scaledDimensions( el ),
3634 to: $.effects.scaledDimensions( el, percent, options.direction || "both" ),
3635 origin: options.origin || [ "middle", "center" ]
3638 // Fade option to support puff
3639 if ( options.fade ) {
3640 newOptions.from.opacity = 1;
3641 newOptions.to.opacity = 0;
3644 $.effects.effect.size.call( this, newOptions, done );
3649 * jQuery UI Effects Puff 1.12.1
3650 * http://jqueryui.com
3652 * Copyright jQuery Foundation and other contributors
3653 * Released under the MIT license.
3654 * http://jquery.org/license
3657 //>>label: Puff Effect
3659 //>>description: Creates a puff effect by scaling the element up and hiding it at the same time.
3660 //>>docs: http://api.jqueryui.com/puff-effect/
3661 //>>demos: http://jqueryui.com/effect/
3665 var effectsEffectPuff = $.effects.define( "puff", "hide", function( options, done ) {
3666 var newOptions = $.extend( true, {}, options, {
3668 percent: parseInt( options.percent, 10 ) || 150
3671 $.effects.effect.scale.call( this, newOptions, done );
3676 * jQuery UI Effects Pulsate 1.12.1
3677 * http://jqueryui.com
3679 * Copyright jQuery Foundation and other contributors
3680 * Released under the MIT license.
3681 * http://jquery.org/license
3684 //>>label: Pulsate Effect
3686 //>>description: Pulsates an element n times by changing the opacity to zero and back.
3687 //>>docs: http://api.jqueryui.com/pulsate-effect/
3688 //>>demos: http://jqueryui.com/effect/
3692 var effectsEffectPulsate = $.effects.define( "pulsate", "show", function( options, done ) {
3693 var element = $( this ),
3694 mode = options.mode,
3695 show = mode === "show",
3696 hide = mode === "hide",
3697 showhide = show || hide,
3699 // Showing or hiding leaves off the "last" animation
3700 anims = ( ( options.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
3701 duration = options.duration / anims,
3704 queuelen = element.queue().length;
3706 if ( show || !element.is( ":visible" ) ) {
3707 element.css( "opacity", 0 ).show();
3711 // Anims - 1 opacity "toggles"
3712 for ( ; i < anims; i++ ) {
3713 element.animate( { opacity: animateTo }, duration, options.easing );
3714 animateTo = 1 - animateTo;
3717 element.animate( { opacity: animateTo }, duration, options.easing );
3719 element.queue( done );
3721 $.effects.unshift( element, queuelen, anims + 1 );
3726 * jQuery UI Effects Shake 1.12.1
3727 * http://jqueryui.com
3729 * Copyright jQuery Foundation and other contributors
3730 * Released under the MIT license.
3731 * http://jquery.org/license
3734 //>>label: Shake Effect
3736 //>>description: Shakes an element horizontally or vertically n times.
3737 //>>docs: http://api.jqueryui.com/shake-effect/
3738 //>>demos: http://jqueryui.com/effect/
3742 var effectsEffectShake = $.effects.define( "shake", function( options, done ) {
3745 element = $( this ),
3746 direction = options.direction || "left",
3747 distance = options.distance || 20,
3748 times = options.times || 3,
3749 anims = times * 2 + 1,
3750 speed = Math.round( options.duration / anims ),
3751 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
3752 positiveMotion = ( direction === "up" || direction === "left" ),
3757 queuelen = element.queue().length;
3759 $.effects.createPlaceholder( element );
3762 animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
3763 animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
3764 animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;
3767 element.animate( animation, speed, options.easing );
3770 for ( ; i < times; i++ ) {
3772 .animate( animation1, speed, options.easing )
3773 .animate( animation2, speed, options.easing );
3777 .animate( animation1, speed, options.easing )
3778 .animate( animation, speed / 2, options.easing )
3781 $.effects.unshift( element, queuelen, anims + 1 );
3786 * jQuery UI Effects Slide 1.12.1
3787 * http://jqueryui.com
3789 * Copyright jQuery Foundation and other contributors
3790 * Released under the MIT license.
3791 * http://jquery.org/license
3794 //>>label: Slide Effect
3796 //>>description: Slides an element in and out of the viewport.
3797 //>>docs: http://api.jqueryui.com/slide-effect/
3798 //>>demos: http://jqueryui.com/effect/
3802 var effectsEffectSlide = $.effects.define( "slide", "show", function( options, done ) {
3803 var startClip, startRef,
3804 element = $( this ),
3806 up: [ "bottom", "top" ],
3807 down: [ "top", "bottom" ],
3808 left: [ "right", "left" ],
3809 right: [ "left", "right" ]
3811 mode = options.mode,
3812 direction = options.direction || "left",
3813 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
3814 positiveMotion = ( direction === "up" || direction === "left" ),
3815 distance = options.distance ||
3816 element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ),
3819 $.effects.createPlaceholder( element );
3821 startClip = element.cssClip();
3822 startRef = element.position()[ ref ];
3824 // Define hide animation
3825 animation[ ref ] = ( positiveMotion ? -1 : 1 ) * distance + startRef;
3826 animation.clip = element.cssClip();
3827 animation.clip[ map[ direction ][ 1 ] ] = animation.clip[ map[ direction ][ 0 ] ];
3829 // Reverse the animation if we're showing
3830 if ( mode === "show" ) {
3831 element.cssClip( animation.clip );
3832 element.css( ref, animation[ ref ] );
3833 animation.clip = startClip;
3834 animation[ ref ] = startRef;
3838 element.animate( animation, {
3840 duration: options.duration,
3841 easing: options.easing,
3848 * jQuery UI Effects Transfer 1.12.1
3849 * http://jqueryui.com
3851 * Copyright jQuery Foundation and other contributors
3852 * Released under the MIT license.
3853 * http://jquery.org/license
3856 //>>label: Transfer Effect
3858 //>>description: Displays a transfer effect from one element to another.
3859 //>>docs: http://api.jqueryui.com/transfer-effect/
3860 //>>demos: http://jqueryui.com/effect/
3865 if ( $.uiBackCompat !== false ) {
3866 effect = $.effects.define( "transfer", function( options, done ) {
3867 $( this ).transfer( options, done );
3870 var effectsEffectTransfer = effect;
3874 * jQuery UI Focusable 1.12.1
3875 * http://jqueryui.com
3877 * Copyright jQuery Foundation and other contributors
3878 * Released under the MIT license.
3879 * http://jquery.org/license
3882 //>>label: :focusable Selector
3884 //>>description: Selects elements which can be focused.
3885 //>>docs: http://api.jqueryui.com/focusable-selector/
3890 $.ui.focusable = function( element, hasTabindex ) {
3891 var map, mapName, img, focusableIfVisible, fieldset,
3892 nodeName = element.nodeName.toLowerCase();
3894 if ( "area" === nodeName ) {
3895 map = element.parentNode;
3897 if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
3900 img = $( "img[usemap='#" + mapName + "']" );
3901 return img.length > 0 && img.is( ":visible" );
3904 if ( /^(input|select|textarea|button|object)$/.test( nodeName ) ) {
3905 focusableIfVisible = !element.disabled;
3907 if ( focusableIfVisible ) {
3909 // Form controls within a disabled fieldset are disabled.
3910 // However, controls within the fieldset's legend do not get disabled.
3911 // Since controls generally aren't placed inside legends, we skip
3912 // this portion of the check.
3913 fieldset = $( element ).closest( "fieldset" )[ 0 ];
3915 focusableIfVisible = !fieldset.disabled;
3918 } else if ( "a" === nodeName ) {
3919 focusableIfVisible = element.href || hasTabindex;
3921 focusableIfVisible = hasTabindex;
3924 return focusableIfVisible && $( element ).is( ":visible" ) && visible( $( element ) );
3927 // Support: IE 8 only
3928 // IE 8 doesn't resolve inherit to visible/hidden for computed values
3929 function visible( element ) {
3930 var visibility = element.css( "visibility" );
3931 while ( visibility === "inherit" ) {
3932 element = element.parent();
3933 visibility = element.css( "visibility" );
3935 return visibility !== "hidden";
3938 $.extend( $.expr[ ":" ], {
3939 focusable: function( element ) {
3940 return $.ui.focusable( element, $.attr( element, "tabindex" ) != null );
3944 var focusable = $.ui.focusable;
3949 // Support: IE8 Only
3950 // IE8 does not support the form attribute and when it is supplied. It overwrites the form prop
3951 // with a string, so we need to find the proper form.
3952 var form = $.fn.form = function() {
3953 return typeof this[ 0 ].form === "string" ? this.closest( "form" ) : $( this[ 0 ].form );
3958 * jQuery UI Form Reset Mixin 1.12.1
3959 * http://jqueryui.com
3961 * Copyright jQuery Foundation and other contributors
3962 * Released under the MIT license.
3963 * http://jquery.org/license
3966 //>>label: Form Reset Mixin
3968 //>>description: Refresh input widgets when their form is reset
3969 //>>docs: http://api.jqueryui.com/form-reset-mixin/
3973 var formResetMixin = $.ui.formResetMixin = {
3974 _formResetHandler: function() {
3975 var form = $( this );
3977 // Wait for the form reset to actually happen before refreshing
3978 setTimeout( function() {
3979 var instances = form.data( "ui-form-reset-instances" );
3980 $.each( instances, function() {
3986 _bindFormResetHandler: function() {
3987 this.form = this.element.form();
3988 if ( !this.form.length ) {
3992 var instances = this.form.data( "ui-form-reset-instances" ) || [];
3993 if ( !instances.length ) {
3995 // We don't use _on() here because we use a single event handler per form
3996 this.form.on( "reset.ui-form-reset", this._formResetHandler );
3998 instances.push( this );
3999 this.form.data( "ui-form-reset-instances", instances );
4002 _unbindFormResetHandler: function() {
4003 if ( !this.form.length ) {
4007 var instances = this.form.data( "ui-form-reset-instances" );
4008 instances.splice( $.inArray( this, instances ), 1 );
4009 if ( instances.length ) {
4010 this.form.data( "ui-form-reset-instances", instances );
4013 .removeData( "ui-form-reset-instances" )
4014 .off( "reset.ui-form-reset" );
4021 * jQuery UI Support for jQuery core 1.7.x 1.12.1
4022 * http://jqueryui.com
4024 * Copyright jQuery Foundation and other contributors
4025 * Released under the MIT license.
4026 * http://jquery.org/license
4030 //>>label: jQuery 1.7 Support
4032 //>>description: Support version 1.7.x of jQuery core
4036 // Support: jQuery 1.7 only
4037 // Not a great way to check versions, but since we only support 1.7+ and only
4038 // need to detect <1.8, this is a simple check that should suffice. Checking
4039 // for "1.7." would be a bit safer, but the version string is 1.7, not 1.7.0
4040 // and we'll never reach 1.70.0 (if we do, we certainly won't be supporting
4041 // 1.7 anymore). See #11197 for why we're not using feature detection.
4042 if ( $.fn.jquery.substring( 0, 3 ) === "1.7" ) {
4044 // Setters for .innerWidth(), .innerHeight(), .outerWidth(), .outerHeight()
4045 // Unlike jQuery Core 1.8+, these only support numeric values to set the
4046 // dimensions in pixels
4047 $.each( [ "Width", "Height" ], function( i, name ) {
4048 var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
4049 type = name.toLowerCase(),
4051 innerWidth: $.fn.innerWidth,
4052 innerHeight: $.fn.innerHeight,
4053 outerWidth: $.fn.outerWidth,
4054 outerHeight: $.fn.outerHeight
4057 function reduce( elem, size, border, margin ) {
4058 $.each( side, function() {
4059 size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
4061 size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
4064 size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
4070 $.fn[ "inner" + name ] = function( size ) {
4071 if ( size === undefined ) {
4072 return orig[ "inner" + name ].call( this );
4075 return this.each( function() {
4076 $( this ).css( type, reduce( this, size ) + "px" );
4080 $.fn[ "outer" + name ] = function( size, margin ) {
4081 if ( typeof size !== "number" ) {
4082 return orig[ "outer" + name ].call( this, size );
4085 return this.each( function() {
4086 $( this ).css( type, reduce( this, size, true, margin ) + "px" );
4091 $.fn.addBack = function( selector ) {
4092 return this.add( selector == null ?
4093 this.prevObject : this.prevObject.filter( selector )
4100 * jQuery UI Keycode 1.12.1
4101 * http://jqueryui.com
4103 * Copyright jQuery Foundation and other contributors
4104 * Released under the MIT license.
4105 * http://jquery.org/license
4110 //>>description: Provide keycodes as keynames
4111 //>>docs: http://api.jqueryui.com/jQuery.ui.keyCode/
4114 var keycode = $.ui.keyCode = {
4136 // Internal use only
4137 var escapeSelector = $.ui.escapeSelector = ( function() {
4138 var selectorEscape = /([!"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g;
4139 return function( selector ) {
4140 return selector.replace( selectorEscape, "\\$1" );
4146 * jQuery UI Labels 1.12.1
4147 * http://jqueryui.com
4149 * Copyright jQuery Foundation and other contributors
4150 * Released under the MIT license.
4151 * http://jquery.org/license
4156 //>>description: Find all the labels associated with a given input
4157 //>>docs: http://api.jqueryui.com/labels/
4161 var labels = $.fn.labels = function() {
4162 var ancestor, selector, id, labels, ancestors;
4164 // Check control.labels first
4165 if ( this[ 0 ].labels && this[ 0 ].labels.length ) {
4166 return this.pushStack( this[ 0 ].labels );
4169 // Support: IE <= 11, FF <= 37, Android <= 2.3 only
4170 // Above browsers do not support control.labels. Everything below is to support them
4171 // as well as document fragments. control.labels does not work on document fragments
4172 labels = this.eq( 0 ).parents( "label" );
4174 // Look for the label based on the id
4175 id = this.attr( "id" );
4178 // We don't search against the document in case the element
4179 // is disconnected from the DOM
4180 ancestor = this.eq( 0 ).parents().last();
4182 // Get a full set of top level ancestors
4183 ancestors = ancestor.add( ancestor.length ? ancestor.siblings() : this.siblings() );
4185 // Create a selector for the label based on the id
4186 selector = "label[for='" + $.ui.escapeSelector( id ) + "']";
4188 labels = labels.add( ancestors.find( selector ).addBack( selector ) );
4192 // Return whatever we have found for labels
4193 return this.pushStack( labels );
4198 * jQuery UI Scroll Parent 1.12.1
4199 * http://jqueryui.com
4201 * Copyright jQuery Foundation and other contributors
4202 * Released under the MIT license.
4203 * http://jquery.org/license
4206 //>>label: scrollParent
4208 //>>description: Get the closest ancestor element that is scrollable.
4209 //>>docs: http://api.jqueryui.com/scrollParent/
4213 var scrollParent = $.fn.scrollParent = function( includeHidden ) {
4214 var position = this.css( "position" ),
4215 excludeStaticParent = position === "absolute",
4216 overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/,
4217 scrollParent = this.parents().filter( function() {
4218 var parent = $( this );
4219 if ( excludeStaticParent && parent.css( "position" ) === "static" ) {
4222 return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) +
4223 parent.css( "overflow-x" ) );
4226 return position === "fixed" || !scrollParent.length ?
4227 $( this[ 0 ].ownerDocument || document ) :
4233 * jQuery UI Tabbable 1.12.1
4234 * http://jqueryui.com
4236 * Copyright jQuery Foundation and other contributors
4237 * Released under the MIT license.
4238 * http://jquery.org/license
4241 //>>label: :tabbable Selector
4243 //>>description: Selects elements which can be tabbed to.
4244 //>>docs: http://api.jqueryui.com/tabbable-selector/
4248 var tabbable = $.extend( $.expr[ ":" ], {
4249 tabbable: function( element ) {
4250 var tabIndex = $.attr( element, "tabindex" ),
4251 hasTabindex = tabIndex != null;
4252 return ( !hasTabindex || tabIndex >= 0 ) && $.ui.focusable( element, hasTabindex );
4258 * jQuery UI Unique ID 1.12.1
4259 * http://jqueryui.com
4261 * Copyright jQuery Foundation and other contributors
4262 * Released under the MIT license.
4263 * http://jquery.org/license
4268 //>>description: Functions to generate and remove uniqueId's
4269 //>>docs: http://api.jqueryui.com/uniqueId/
4273 var uniqueId = $.fn.extend( {
4274 uniqueId: ( function() {
4278 return this.each( function() {
4280 this.id = "ui-id-" + ( ++uuid );
4286 removeUniqueId: function() {
4287 return this.each( function() {
4288 if ( /^ui-id-\d+$/.test( this.id ) ) {
4289 $( this ).removeAttr( "id" );
4297 * jQuery UI Accordion 1.12.1
4298 * http://jqueryui.com
4300 * Copyright jQuery Foundation and other contributors
4301 * Released under the MIT license.
4302 * http://jquery.org/license
4305 //>>label: Accordion
4307 // jscs:disable maximumLineLength
4308 //>>description: Displays collapsible content panels for presenting information in a limited amount of space.
4309 // jscs:enable maximumLineLength
4310 //>>docs: http://api.jqueryui.com/accordion/
4311 //>>demos: http://jqueryui.com/accordion/
4312 //>>css.structure: ../../themes/base/core.css
4313 //>>css.structure: ../../themes/base/accordion.css
4314 //>>css.theme: ../../themes/base/theme.css
4318 var widgetsAccordion = $.widget( "ui.accordion", {
4324 "ui-accordion-header": "ui-corner-top",
4325 "ui-accordion-header-collapsed": "ui-corner-all",
4326 "ui-accordion-content": "ui-corner-bottom"
4330 header: "> li > :first-child, > :not(li):even",
4331 heightStyle: "auto",
4333 activeHeader: "ui-icon-triangle-1-s",
4334 header: "ui-icon-triangle-1-e"
4339 beforeActivate: null
4343 borderTopWidth: "hide",
4344 borderBottomWidth: "hide",
4346 paddingBottom: "hide",
4351 borderTopWidth: "show",
4352 borderBottomWidth: "show",
4354 paddingBottom: "show",
4358 _create: function() {
4359 var options = this.options;
4361 this.prevShow = this.prevHide = $();
4362 this._addClass( "ui-accordion", "ui-widget ui-helper-reset" );
4363 this.element.attr( "role", "tablist" );
4365 // Don't allow collapsible: false and active: false / null
4366 if ( !options.collapsible && ( options.active === false || options.active == null ) ) {
4370 this._processPanels();
4372 // handle negative values
4373 if ( options.active < 0 ) {
4374 options.active += this.headers.length;
4379 _getCreateEventData: function() {
4381 header: this.active,
4382 panel: !this.active.length ? $() : this.active.next()
4386 _createIcons: function() {
4388 icons = this.options.icons;
4391 icon = $( "<span>" );
4392 this._addClass( icon, "ui-accordion-header-icon", "ui-icon " + icons.header );
4393 icon.prependTo( this.headers );
4394 children = this.active.children( ".ui-accordion-header-icon" );
4395 this._removeClass( children, icons.header )
4396 ._addClass( children, null, icons.activeHeader )
4397 ._addClass( this.headers, "ui-accordion-icons" );
4401 _destroyIcons: function() {
4402 this._removeClass( this.headers, "ui-accordion-icons" );
4403 this.headers.children( ".ui-accordion-header-icon" ).remove();
4406 _destroy: function() {
4409 // Clean up main element
4410 this.element.removeAttr( "role" );
4414 .removeAttr( "role aria-expanded aria-selected aria-controls tabIndex" )
4417 this._destroyIcons();
4419 // Clean up content panels
4420 contents = this.headers.next()
4421 .css( "display", "" )
4422 .removeAttr( "role aria-hidden aria-labelledby" )
4425 if ( this.options.heightStyle !== "content" ) {
4426 contents.css( "height", "" );
4430 _setOption: function( key, value ) {
4431 if ( key === "active" ) {
4433 // _activate() will handle invalid values and update this.options
4434 this._activate( value );
4438 if ( key === "event" ) {
4439 if ( this.options.event ) {
4440 this._off( this.headers, this.options.event );
4442 this._setupEvents( value );
4445 this._super( key, value );
4447 // Setting collapsible: false while collapsed; open first panel
4448 if ( key === "collapsible" && !value && this.options.active === false ) {
4449 this._activate( 0 );
4452 if ( key === "icons" ) {
4453 this._destroyIcons();
4455 this._createIcons();
4460 _setOptionDisabled: function( value ) {
4461 this._super( value );
4463 this.element.attr( "aria-disabled", value );
4465 // Support: IE8 Only
4466 // #5332 / #6059 - opacity doesn't cascade to positioned elements in IE
4467 // so we need to add the disabled class to the headers and panels
4468 this._toggleClass( null, "ui-state-disabled", !!value );
4469 this._toggleClass( this.headers.add( this.headers.next() ), null, "ui-state-disabled",
4473 _keydown: function( event ) {
4474 if ( event.altKey || event.ctrlKey ) {
4478 var keyCode = $.ui.keyCode,
4479 length = this.headers.length,
4480 currentIndex = this.headers.index( event.target ),
4483 switch ( event.keyCode ) {
4486 toFocus = this.headers[ ( currentIndex + 1 ) % length ];
4490 toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
4494 this._eventHandler( event );
4497 toFocus = this.headers[ 0 ];
4500 toFocus = this.headers[ length - 1 ];
4505 $( event.target ).attr( "tabIndex", -1 );
4506 $( toFocus ).attr( "tabIndex", 0 );
4507 $( toFocus ).trigger( "focus" );
4508 event.preventDefault();
4512 _panelKeyDown: function( event ) {
4513 if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
4514 $( event.currentTarget ).prev().trigger( "focus" );
4518 refresh: function() {
4519 var options = this.options;
4520 this._processPanels();
4522 // Was collapsed or no panel
4523 if ( ( options.active === false && options.collapsible === true ) ||
4524 !this.headers.length ) {
4525 options.active = false;
4528 // active false only when collapsible is true
4529 } else if ( options.active === false ) {
4530 this._activate( 0 );
4532 // was active, but active panel is gone
4533 } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
4535 // all remaining panel are disabled
4536 if ( this.headers.length === this.headers.find( ".ui-state-disabled" ).length ) {
4537 options.active = false;
4540 // activate previous panel
4542 this._activate( Math.max( 0, options.active - 1 ) );
4545 // was active, active panel still exists
4548 // make sure active index is correct
4549 options.active = this.headers.index( this.active );
4552 this._destroyIcons();
4557 _processPanels: function() {
4558 var prevHeaders = this.headers,
4559 prevPanels = this.panels;
4561 this.headers = this.element.find( this.options.header );
4562 this._addClass( this.headers, "ui-accordion-header ui-accordion-header-collapsed",
4563 "ui-state-default" );
4565 this.panels = this.headers.next().filter( ":not(.ui-accordion-content-active)" ).hide();
4566 this._addClass( this.panels, "ui-accordion-content", "ui-helper-reset ui-widget-content" );
4568 // Avoid memory leaks (#10056)
4570 this._off( prevHeaders.not( this.headers ) );
4571 this._off( prevPanels.not( this.panels ) );
4575 _refresh: function() {
4577 options = this.options,
4578 heightStyle = options.heightStyle,
4579 parent = this.element.parent();
4581 this.active = this._findActive( options.active );
4582 this._addClass( this.active, "ui-accordion-header-active", "ui-state-active" )
4583 ._removeClass( this.active, "ui-accordion-header-collapsed" );
4584 this._addClass( this.active.next(), "ui-accordion-content-active" );
4585 this.active.next().show();
4588 .attr( "role", "tab" )
4590 var header = $( this ),
4591 headerId = header.uniqueId().attr( "id" ),
4592 panel = header.next(),
4593 panelId = panel.uniqueId().attr( "id" );
4594 header.attr( "aria-controls", panelId );
4595 panel.attr( "aria-labelledby", headerId );
4598 .attr( "role", "tabpanel" );
4603 "aria-selected": "false",
4604 "aria-expanded": "false",
4609 "aria-hidden": "true"
4613 // Make sure at least one header is in the tab order
4614 if ( !this.active.length ) {
4615 this.headers.eq( 0 ).attr( "tabIndex", 0 );
4618 "aria-selected": "true",
4619 "aria-expanded": "true",
4624 "aria-hidden": "false"
4628 this._createIcons();
4630 this._setupEvents( options.event );
4632 if ( heightStyle === "fill" ) {
4633 maxHeight = parent.height();
4634 this.element.siblings( ":visible" ).each( function() {
4635 var elem = $( this ),
4636 position = elem.css( "position" );
4638 if ( position === "absolute" || position === "fixed" ) {
4641 maxHeight -= elem.outerHeight( true );
4644 this.headers.each( function() {
4645 maxHeight -= $( this ).outerHeight( true );
4650 $( this ).height( Math.max( 0, maxHeight -
4651 $( this ).innerHeight() + $( this ).height() ) );
4653 .css( "overflow", "auto" );
4654 } else if ( heightStyle === "auto" ) {
4658 var isVisible = $( this ).is( ":visible" );
4662 maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
4667 .height( maxHeight );
4671 _activate: function( index ) {
4672 var active = this._findActive( index )[ 0 ];
4674 // Trying to activate the already active panel
4675 if ( active === this.active[ 0 ] ) {
4679 // Trying to collapse, simulate a click on the currently active header
4680 active = active || this.active[ 0 ];
4682 this._eventHandler( {
4684 currentTarget: active,
4685 preventDefault: $.noop
4689 _findActive: function( selector ) {
4690 return typeof selector === "number" ? this.headers.eq( selector ) : $();
4693 _setupEvents: function( event ) {
4698 $.each( event.split( " " ), function( index, eventName ) {
4699 events[ eventName ] = "_eventHandler";
4703 this._off( this.headers.add( this.headers.next() ) );
4704 this._on( this.headers, events );
4705 this._on( this.headers.next(), { keydown: "_panelKeyDown" } );
4706 this._hoverable( this.headers );
4707 this._focusable( this.headers );
4710 _eventHandler: function( event ) {
4711 var activeChildren, clickedChildren,
4712 options = this.options,
4713 active = this.active,
4714 clicked = $( event.currentTarget ),
4715 clickedIsActive = clicked[ 0 ] === active[ 0 ],
4716 collapsing = clickedIsActive && options.collapsible,
4717 toShow = collapsing ? $() : clicked.next(),
4718 toHide = active.next(),
4722 newHeader: collapsing ? $() : clicked,
4726 event.preventDefault();
4730 // click on active header, but not collapsible
4731 ( clickedIsActive && !options.collapsible ) ||
4733 // allow canceling activation
4734 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
4738 options.active = collapsing ? false : this.headers.index( clicked );
4740 // When the call to ._toggle() comes after the class changes
4741 // it causes a very odd bug in IE 8 (see #6720)
4742 this.active = clickedIsActive ? $() : clicked;
4743 this._toggle( eventData );
4746 // corner classes on the previously active header stay after the animation
4747 this._removeClass( active, "ui-accordion-header-active", "ui-state-active" );
4748 if ( options.icons ) {
4749 activeChildren = active.children( ".ui-accordion-header-icon" );
4750 this._removeClass( activeChildren, null, options.icons.activeHeader )
4751 ._addClass( activeChildren, null, options.icons.header );
4754 if ( !clickedIsActive ) {
4755 this._removeClass( clicked, "ui-accordion-header-collapsed" )
4756 ._addClass( clicked, "ui-accordion-header-active", "ui-state-active" );
4757 if ( options.icons ) {
4758 clickedChildren = clicked.children( ".ui-accordion-header-icon" );
4759 this._removeClass( clickedChildren, null, options.icons.header )
4760 ._addClass( clickedChildren, null, options.icons.activeHeader );
4763 this._addClass( clicked.next(), "ui-accordion-content-active" );
4767 _toggle: function( data ) {
4768 var toShow = data.newPanel,
4769 toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
4771 // Handle activating a panel during the animation for another activation
4772 this.prevShow.add( this.prevHide ).stop( true, true );
4773 this.prevShow = toShow;
4774 this.prevHide = toHide;
4776 if ( this.options.animate ) {
4777 this._animate( toShow, toHide, data );
4781 this._toggleComplete( data );
4785 "aria-hidden": "true"
4787 toHide.prev().attr( {
4788 "aria-selected": "false",
4789 "aria-expanded": "false"
4792 // if we're switching panels, remove the old header from the tab order
4793 // if we're opening from collapsed state, remove the previous header from the tab order
4794 // if we're collapsing, then keep the collapsing header in the tab order
4795 if ( toShow.length && toHide.length ) {
4796 toHide.prev().attr( {
4798 "aria-expanded": "false"
4800 } else if ( toShow.length ) {
4801 this.headers.filter( function() {
4802 return parseInt( $( this ).attr( "tabIndex" ), 10 ) === 0;
4804 .attr( "tabIndex", -1 );
4808 .attr( "aria-hidden", "false" )
4811 "aria-selected": "true",
4812 "aria-expanded": "true",
4817 _animate: function( toShow, toHide, data ) {
4818 var total, easing, duration,
4821 boxSizing = toShow.css( "box-sizing" ),
4822 down = toShow.length &&
4823 ( !toHide.length || ( toShow.index() < toHide.index() ) ),
4824 animate = this.options.animate || {},
4825 options = down && animate.down || animate,
4826 complete = function() {
4827 that._toggleComplete( data );
4830 if ( typeof options === "number" ) {
4833 if ( typeof options === "string" ) {
4837 // fall back from options to animation in case of partial down settings
4838 easing = easing || options.easing || animate.easing;
4839 duration = duration || options.duration || animate.duration;
4841 if ( !toHide.length ) {
4842 return toShow.animate( this.showProps, duration, easing, complete );
4844 if ( !toShow.length ) {
4845 return toHide.animate( this.hideProps, duration, easing, complete );
4848 total = toShow.show().outerHeight();
4849 toHide.animate( this.hideProps, {
4852 step: function( now, fx ) {
4853 fx.now = Math.round( now );
4858 .animate( this.showProps, {
4862 step: function( now, fx ) {
4863 fx.now = Math.round( now );
4864 if ( fx.prop !== "height" ) {
4865 if ( boxSizing === "content-box" ) {
4868 } else if ( that.options.heightStyle !== "content" ) {
4869 fx.now = Math.round( total - toHide.outerHeight() - adjust );
4876 _toggleComplete: function( data ) {
4877 var toHide = data.oldPanel,
4878 prev = toHide.prev();
4880 this._removeClass( toHide, "ui-accordion-content-active" );
4881 this._removeClass( prev, "ui-accordion-header-active" )
4882 ._addClass( prev, "ui-accordion-header-collapsed" );
4884 // Work around for rendering bug in IE (#5421)
4885 if ( toHide.length ) {
4886 toHide.parent()[ 0 ].className = toHide.parent()[ 0 ].className;
4888 this._trigger( "activate", null, data );
4894 var safeActiveElement = $.ui.safeActiveElement = function( document ) {
4897 // Support: IE 9 only
4898 // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
4900 activeElement = document.activeElement;
4902 activeElement = document.body;
4905 // Support: IE 9 - 11 only
4906 // IE may return null instead of an element
4907 // Interestingly, this only seems to occur when NOT in an iframe
4908 if ( !activeElement ) {
4909 activeElement = document.body;
4912 // Support: IE 11 only
4913 // IE11 returns a seemingly empty object in some cases when accessing
4914 // document.activeElement from an <iframe>
4915 if ( !activeElement.nodeName ) {
4916 activeElement = document.body;
4919 return activeElement;
4924 * jQuery UI Menu 1.12.1
4925 * http://jqueryui.com
4927 * Copyright jQuery Foundation and other contributors
4928 * Released under the MIT license.
4929 * http://jquery.org/license
4934 //>>description: Creates nestable menus.
4935 //>>docs: http://api.jqueryui.com/menu/
4936 //>>demos: http://jqueryui.com/menu/
4937 //>>css.structure: ../../themes/base/core.css
4938 //>>css.structure: ../../themes/base/menu.css
4939 //>>css.theme: ../../themes/base/theme.css
4943 var widgetsMenu = $.widget( "ui.menu", {
4945 defaultElement: "<ul>",
4949 submenu: "ui-icon-caret-1-e"
4965 _create: function() {
4966 this.activeMenu = this.element;
4968 // Flag used to prevent firing of the click handler
4969 // as the event bubbles up through nested menus
4970 this.mouseHandled = false;
4974 role: this.options.role,
4978 this._addClass( "ui-menu", "ui-widget ui-widget-content" );
4981 // Prevent focus from sticking to links inside menu after clicking
4982 // them (focus should always stay on UL during navigation).
4983 "mousedown .ui-menu-item": function( event ) {
4984 event.preventDefault();
4986 "click .ui-menu-item": function( event ) {
4987 var target = $( event.target );
4988 var active = $( $.ui.safeActiveElement( this.document[ 0 ] ) );
4989 if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
4990 this.select( event );
4992 // Only set the mouseHandled flag if the event will bubble, see #9469.
4993 if ( !event.isPropagationStopped() ) {
4994 this.mouseHandled = true;
4997 // Open submenu on click
4998 if ( target.has( ".ui-menu" ).length ) {
4999 this.expand( event );
5000 } else if ( !this.element.is( ":focus" ) &&
5001 active.closest( ".ui-menu" ).length ) {
5003 // Redirect focus to the menu
5004 this.element.trigger( "focus", [ true ] );
5006 // If the active item is on the top level, let it stay active.
5007 // Otherwise, blur the active item since it is no longer visible.
5008 if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
5009 clearTimeout( this.timer );
5014 "mouseenter .ui-menu-item": function( event ) {
5016 // Ignore mouse events while typeahead is active, see #10458.
5017 // Prevents focusing the wrong item when typeahead causes a scroll while the mouse
5018 // is over an item in the menu
5019 if ( this.previousFilter ) {
5023 var actualTarget = $( event.target ).closest( ".ui-menu-item" ),
5024 target = $( event.currentTarget );
5026 // Ignore bubbled events on parent items, see #11641
5027 if ( actualTarget[ 0 ] !== target[ 0 ] ) {
5031 // Remove ui-state-active class from siblings of the newly focused menu item
5032 // to avoid a jump caused by adjacent elements both having a class with a border
5033 this._removeClass( target.siblings().children( ".ui-state-active" ),
5034 null, "ui-state-active" );
5035 this.focus( event, target );
5037 mouseleave: "collapseAll",
5038 "mouseleave .ui-menu": "collapseAll",
5039 focus: function( event, keepActiveItem ) {
5041 // If there's already an active item, keep it active
5042 // If not, activate the first item
5043 var item = this.active || this.element.find( this.options.items ).eq( 0 );
5045 if ( !keepActiveItem ) {
5046 this.focus( event, item );
5049 blur: function( event ) {
5050 this._delay( function() {
5051 var notContained = !$.contains(
5053 $.ui.safeActiveElement( this.document[ 0 ] )
5055 if ( notContained ) {
5056 this.collapseAll( event );
5065 // Clicks outside of a menu collapse any open menus
5066 this._on( this.document, {
5067 click: function( event ) {
5068 if ( this._closeOnDocumentClick( event ) ) {
5069 this.collapseAll( event );
5072 // Reset the mouseHandled flag
5073 this.mouseHandled = false;
5078 _destroy: function() {
5079 var items = this.element.find( ".ui-menu-item" )
5080 .removeAttr( "role aria-disabled" ),
5081 submenus = items.children( ".ui-menu-item-wrapper" )
5083 .removeAttr( "tabIndex role aria-haspopup" );
5085 // Destroy (sub)menus
5087 .removeAttr( "aria-activedescendant" )
5088 .find( ".ui-menu" ).addBack()
5089 .removeAttr( "role aria-labelledby aria-expanded aria-hidden aria-disabled " +
5094 submenus.children().each( function() {
5095 var elem = $( this );
5096 if ( elem.data( "ui-menu-submenu-caret" ) ) {
5102 _keydown: function( event ) {
5103 var match, prev, character, skip,
5104 preventDefault = true;
5106 switch ( event.keyCode ) {
5107 case $.ui.keyCode.PAGE_UP:
5108 this.previousPage( event );
5110 case $.ui.keyCode.PAGE_DOWN:
5111 this.nextPage( event );
5113 case $.ui.keyCode.HOME:
5114 this._move( "first", "first", event );
5116 case $.ui.keyCode.END:
5117 this._move( "last", "last", event );
5119 case $.ui.keyCode.UP:
5120 this.previous( event );
5122 case $.ui.keyCode.DOWN:
5125 case $.ui.keyCode.LEFT:
5126 this.collapse( event );
5128 case $.ui.keyCode.RIGHT:
5129 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
5130 this.expand( event );
5133 case $.ui.keyCode.ENTER:
5134 case $.ui.keyCode.SPACE:
5135 this._activate( event );
5137 case $.ui.keyCode.ESCAPE:
5138 this.collapse( event );
5141 preventDefault = false;
5142 prev = this.previousFilter || "";
5145 // Support number pad values
5146 character = event.keyCode >= 96 && event.keyCode <= 105 ?
5147 ( event.keyCode - 96 ).toString() : String.fromCharCode( event.keyCode );
5149 clearTimeout( this.filterTimer );
5151 if ( character === prev ) {
5154 character = prev + character;
5157 match = this._filterMenuItems( character );
5158 match = skip && match.index( this.active.next() ) !== -1 ?
5159 this.active.nextAll( ".ui-menu-item" ) :
5162 // If no matches on the current filter, reset to the last character pressed
5163 // to move down the menu to the first item that starts with that character
5164 if ( !match.length ) {
5165 character = String.fromCharCode( event.keyCode );
5166 match = this._filterMenuItems( character );
5169 if ( match.length ) {
5170 this.focus( event, match );
5171 this.previousFilter = character;
5172 this.filterTimer = this._delay( function() {
5173 delete this.previousFilter;
5176 delete this.previousFilter;
5180 if ( preventDefault ) {
5181 event.preventDefault();
5185 _activate: function( event ) {
5186 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
5187 if ( this.active.children( "[aria-haspopup='true']" ).length ) {
5188 this.expand( event );
5190 this.select( event );
5195 refresh: function() {
5196 var menus, items, newSubmenus, newItems, newWrappers,
5198 icon = this.options.icons.submenu,
5199 submenus = this.element.find( this.options.menus );
5201 this._toggleClass( "ui-menu-icons", null, !!this.element.find( ".ui-icon" ).length );
5203 // Initialize nested menus
5204 newSubmenus = submenus.filter( ":not(.ui-menu)" )
5207 role: this.options.role,
5208 "aria-hidden": "true",
5209 "aria-expanded": "false"
5212 var menu = $( this ),
5214 submenuCaret = $( "<span>" ).data( "ui-menu-submenu-caret", true );
5216 that._addClass( submenuCaret, "ui-menu-icon", "ui-icon " + icon );
5218 .attr( "aria-haspopup", "true" )
5219 .prepend( submenuCaret );
5220 menu.attr( "aria-labelledby", item.attr( "id" ) );
5223 this._addClass( newSubmenus, "ui-menu", "ui-widget ui-widget-content ui-front" );
5225 menus = submenus.add( this.element );
5226 items = menus.find( this.options.items );
5228 // Initialize menu-items containing spaces and/or dashes only as dividers
5229 items.not( ".ui-menu-item" ).each( function() {
5230 var item = $( this );
5231 if ( that._isDivider( item ) ) {
5232 that._addClass( item, "ui-menu-divider", "ui-widget-content" );
5236 // Don't refresh list items that are already adapted
5237 newItems = items.not( ".ui-menu-item, .ui-menu-divider" );
5238 newWrappers = newItems.children()
5243 role: this._itemRole()
5245 this._addClass( newItems, "ui-menu-item" )
5246 ._addClass( newWrappers, "ui-menu-item-wrapper" );
5248 // Add aria-disabled attribute to any disabled menu item
5249 items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
5251 // If the active item has been removed, blur the menu
5252 if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
5257 _itemRole: function() {
5261 }[ this.options.role ];
5264 _setOption: function( key, value ) {
5265 if ( key === "icons" ) {
5266 var icons = this.element.find( ".ui-menu-icon" );
5267 this._removeClass( icons, null, this.options.icons.submenu )
5268 ._addClass( icons, null, value.submenu );
5270 this._super( key, value );
5273 _setOptionDisabled: function( value ) {
5274 this._super( value );
5276 this.element.attr( "aria-disabled", String( value ) );
5277 this._toggleClass( null, "ui-state-disabled", !!value );
5280 focus: function( event, item ) {
5281 var nested, focused, activeParent;
5282 this.blur( event, event && event.type === "focus" );
5284 this._scrollIntoView( item );
5286 this.active = item.first();
5288 focused = this.active.children( ".ui-menu-item-wrapper" );
5289 this._addClass( focused, null, "ui-state-active" );
5291 // Only update aria-activedescendant if there's a role
5292 // otherwise we assume focus is managed elsewhere
5293 if ( this.options.role ) {
5294 this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
5297 // Highlight active parent menu item, if any
5298 activeParent = this.active
5300 .closest( ".ui-menu-item" )
5301 .children( ".ui-menu-item-wrapper" );
5302 this._addClass( activeParent, null, "ui-state-active" );
5304 if ( event && event.type === "keydown" ) {
5307 this.timer = this._delay( function() {
5312 nested = item.children( ".ui-menu" );
5313 if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) {
5314 this._startOpening( nested );
5316 this.activeMenu = item.parent();
5318 this._trigger( "focus", event, { item: item } );
5321 _scrollIntoView: function( item ) {
5322 var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
5323 if ( this._hasScroll() ) {
5324 borderTop = parseFloat( $.css( this.activeMenu[ 0 ], "borderTopWidth" ) ) || 0;
5325 paddingTop = parseFloat( $.css( this.activeMenu[ 0 ], "paddingTop" ) ) || 0;
5326 offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
5327 scroll = this.activeMenu.scrollTop();
5328 elementHeight = this.activeMenu.height();
5329 itemHeight = item.outerHeight();
5332 this.activeMenu.scrollTop( scroll + offset );
5333 } else if ( offset + itemHeight > elementHeight ) {
5334 this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
5339 blur: function( event, fromFocus ) {
5341 clearTimeout( this.timer );
5344 if ( !this.active ) {
5348 this._removeClass( this.active.children( ".ui-menu-item-wrapper" ),
5349 null, "ui-state-active" );
5351 this._trigger( "blur", event, { item: this.active } );
5355 _startOpening: function( submenu ) {
5356 clearTimeout( this.timer );
5358 // Don't open if already open fixes a Firefox bug that caused a .5 pixel
5359 // shift in the submenu position when mousing over the caret icon
5360 if ( submenu.attr( "aria-hidden" ) !== "true" ) {
5364 this.timer = this._delay( function() {
5366 this._open( submenu );
5370 _open: function( submenu ) {
5371 var position = $.extend( {
5373 }, this.options.position );
5375 clearTimeout( this.timer );
5376 this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
5378 .attr( "aria-hidden", "true" );
5382 .removeAttr( "aria-hidden" )
5383 .attr( "aria-expanded", "true" )
5384 .position( position );
5387 collapseAll: function( event, all ) {
5388 clearTimeout( this.timer );
5389 this.timer = this._delay( function() {
5391 // If we were passed an event, look for the submenu that contains the event
5392 var currentMenu = all ? this.element :
5393 $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
5395 // If we found no valid submenu ancestor, use the main menu to close all
5397 if ( !currentMenu.length ) {
5398 currentMenu = this.element;
5401 this._close( currentMenu );
5405 // Work around active item staying active after menu is blurred
5406 this._removeClass( currentMenu.find( ".ui-state-active" ), null, "ui-state-active" );
5408 this.activeMenu = currentMenu;
5412 // With no arguments, closes the currently active menu - if nothing is active
5413 // it closes all menus. If passed an argument, it will search for menus BELOW
5414 _close: function( startMenu ) {
5416 startMenu = this.active ? this.active.parent() : this.element;
5419 startMenu.find( ".ui-menu" )
5421 .attr( "aria-hidden", "true" )
5422 .attr( "aria-expanded", "false" );
5425 _closeOnDocumentClick: function( event ) {
5426 return !$( event.target ).closest( ".ui-menu" ).length;
5429 _isDivider: function( item ) {
5431 // Match hyphen, em dash, en dash
5432 return !/[^\-\u2014\u2013\s]/.test( item.text() );
5435 collapse: function( event ) {
5436 var newItem = this.active &&
5437 this.active.parent().closest( ".ui-menu-item", this.element );
5438 if ( newItem && newItem.length ) {
5440 this.focus( event, newItem );
5444 expand: function( event ) {
5445 var newItem = this.active &&
5447 .children( ".ui-menu " )
5448 .find( this.options.items )
5451 if ( newItem && newItem.length ) {
5452 this._open( newItem.parent() );
5454 // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
5455 this._delay( function() {
5456 this.focus( event, newItem );
5461 next: function( event ) {
5462 this._move( "next", "first", event );
5465 previous: function( event ) {
5466 this._move( "prev", "last", event );
5469 isFirstItem: function() {
5470 return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
5473 isLastItem: function() {
5474 return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
5477 _move: function( direction, filter, event ) {
5479 if ( this.active ) {
5480 if ( direction === "first" || direction === "last" ) {
5482 [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
5486 [ direction + "All" ]( ".ui-menu-item" )
5490 if ( !next || !next.length || !this.active ) {
5491 next = this.activeMenu.find( this.options.items )[ filter ]();
5494 this.focus( event, next );
5497 nextPage: function( event ) {
5498 var item, base, height;
5500 if ( !this.active ) {
5504 if ( this.isLastItem() ) {
5507 if ( this._hasScroll() ) {
5508 base = this.active.offset().top;
5509 height = this.element.height();
5510 this.active.nextAll( ".ui-menu-item" ).each( function() {
5512 return item.offset().top - base - height < 0;
5515 this.focus( event, item );
5517 this.focus( event, this.activeMenu.find( this.options.items )
5518 [ !this.active ? "first" : "last" ]() );
5522 previousPage: function( event ) {
5523 var item, base, height;
5524 if ( !this.active ) {
5528 if ( this.isFirstItem() ) {
5531 if ( this._hasScroll() ) {
5532 base = this.active.offset().top;
5533 height = this.element.height();
5534 this.active.prevAll( ".ui-menu-item" ).each( function() {
5536 return item.offset().top - base + height > 0;
5539 this.focus( event, item );
5541 this.focus( event, this.activeMenu.find( this.options.items ).first() );
5545 _hasScroll: function() {
5546 return this.element.outerHeight() < this.element.prop( "scrollHeight" );
5549 select: function( event ) {
5551 // TODO: It should never be possible to not have an active item at this
5552 // point, but the tests don't trigger mouseenter before click.
5553 this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
5554 var ui = { item: this.active };
5555 if ( !this.active.has( ".ui-menu" ).length ) {
5556 this.collapseAll( event, true );
5558 this._trigger( "select", event, ui );
5561 _filterMenuItems: function( character ) {
5562 var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ),
5563 regex = new RegExp( "^" + escapedCharacter, "i" );
5565 return this.activeMenu
5566 .find( this.options.items )
5568 // Only match on items, not dividers or other content (#10571)
5569 .filter( ".ui-menu-item" )
5570 .filter( function() {
5572 $.trim( $( this ).children( ".ui-menu-item-wrapper" ).text() ) );
5579 * jQuery UI Autocomplete 1.12.1
5580 * http://jqueryui.com
5582 * Copyright jQuery Foundation and other contributors
5583 * Released under the MIT license.
5584 * http://jquery.org/license
5587 //>>label: Autocomplete
5589 //>>description: Lists suggested words as the user is typing.
5590 //>>docs: http://api.jqueryui.com/autocomplete/
5591 //>>demos: http://jqueryui.com/autocomplete/
5592 //>>css.structure: ../../themes/base/core.css
5593 //>>css.structure: ../../themes/base/autocomplete.css
5594 //>>css.theme: ../../themes/base/theme.css
5598 $.widget( "ui.autocomplete", {
5600 defaultElement: "<input>",
5626 _create: function() {
5628 // Some browsers only repeat keydown events, not keypress events,
5629 // so we use the suppressKeyPress flag to determine if we've already
5630 // handled the keydown event. #7269
5631 // Unfortunately the code for & in keypress is the same as the up arrow,
5632 // so we use the suppressKeyPressRepeat flag to avoid handling keypress
5633 // events when we know the keydown event was used to modify the
5634 // search term. #7799
5635 var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
5636 nodeName = this.element[ 0 ].nodeName.toLowerCase(),
5637 isTextarea = nodeName === "textarea",
5638 isInput = nodeName === "input";
5640 // Textareas are always multi-line
5641 // Inputs are always single-line, even if inside a contentEditable element
5642 // IE also treats inputs as contentEditable
5643 // All other element types are determined by whether or not they're contentEditable
5644 this.isMultiLine = isTextarea || !isInput && this._isContentEditable( this.element );
5646 this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
5647 this.isNewMenu = true;
5649 this._addClass( "ui-autocomplete-input" );
5650 this.element.attr( "autocomplete", "off" );
5652 this._on( this.element, {
5653 keydown: function( event ) {
5654 if ( this.element.prop( "readOnly" ) ) {
5655 suppressKeyPress = true;
5656 suppressInput = true;
5657 suppressKeyPressRepeat = true;
5661 suppressKeyPress = false;
5662 suppressInput = false;
5663 suppressKeyPressRepeat = false;
5664 var keyCode = $.ui.keyCode;
5665 switch ( event.keyCode ) {
5666 case keyCode.PAGE_UP:
5667 suppressKeyPress = true;
5668 this._move( "previousPage", event );
5670 case keyCode.PAGE_DOWN:
5671 suppressKeyPress = true;
5672 this._move( "nextPage", event );
5675 suppressKeyPress = true;
5676 this._keyEvent( "previous", event );
5679 suppressKeyPress = true;
5680 this._keyEvent( "next", event );
5684 // when menu is open and has focus
5685 if ( this.menu.active ) {
5687 // #6055 - Opera still allows the keypress to occur
5688 // which causes forms to submit
5689 suppressKeyPress = true;
5690 event.preventDefault();
5691 this.menu.select( event );
5695 if ( this.menu.active ) {
5696 this.menu.select( event );
5699 case keyCode.ESCAPE:
5700 if ( this.menu.element.is( ":visible" ) ) {
5701 if ( !this.isMultiLine ) {
5702 this._value( this.term );
5704 this.close( event );
5706 // Different browsers have different default behavior for escape
5707 // Single press can mean undo or clear
5708 // Double press in IE means clear the whole form
5709 event.preventDefault();
5713 suppressKeyPressRepeat = true;
5715 // search timeout should be triggered before the input value is changed
5716 this._searchTimeout( event );
5720 keypress: function( event ) {
5721 if ( suppressKeyPress ) {
5722 suppressKeyPress = false;
5723 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
5724 event.preventDefault();
5728 if ( suppressKeyPressRepeat ) {
5732 // Replicate some key handlers to allow them to repeat in Firefox and Opera
5733 var keyCode = $.ui.keyCode;
5734 switch ( event.keyCode ) {
5735 case keyCode.PAGE_UP:
5736 this._move( "previousPage", event );
5738 case keyCode.PAGE_DOWN:
5739 this._move( "nextPage", event );
5742 this._keyEvent( "previous", event );
5745 this._keyEvent( "next", event );
5749 input: function( event ) {
5750 if ( suppressInput ) {
5751 suppressInput = false;
5752 event.preventDefault();
5755 this._searchTimeout( event );
5758 this.selectedItem = null;
5759 this.previous = this._value();
5761 blur: function( event ) {
5762 if ( this.cancelBlur ) {
5763 delete this.cancelBlur;
5767 clearTimeout( this.searching );
5768 this.close( event );
5769 this._change( event );
5774 this.menu = $( "<ul>" )
5775 .appendTo( this._appendTo() )
5778 // disable ARIA support, the live region takes care of that
5782 .menu( "instance" );
5784 this._addClass( this.menu.element, "ui-autocomplete", "ui-front" );
5785 this._on( this.menu.element, {
5786 mousedown: function( event ) {
5788 // prevent moving focus out of the text field
5789 event.preventDefault();
5791 // IE doesn't prevent moving focus even with event.preventDefault()
5792 // so we set a flag to know when we should ignore the blur event
5793 this.cancelBlur = true;
5794 this._delay( function() {
5795 delete this.cancelBlur;
5797 // Support: IE 8 only
5798 // Right clicking a menu item or selecting text from the menu items will
5799 // result in focus moving out of the input. However, we've already received
5800 // and ignored the blur event because of the cancelBlur flag set above. So
5801 // we restore focus to ensure that the menu closes properly based on the user's
5803 if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) {
5804 this.element.trigger( "focus" );
5808 menufocus: function( event, ui ) {
5812 // Prevent accidental activation of menu items in Firefox (#7024 #9118)
5813 if ( this.isNewMenu ) {
5814 this.isNewMenu = false;
5815 if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
5818 this.document.one( "mousemove", function() {
5819 $( event.target ).trigger( event.originalEvent );
5826 item = ui.item.data( "ui-autocomplete-item" );
5827 if ( false !== this._trigger( "focus", event, { item: item } ) ) {
5829 // use value to match what will end up in the input, if it was a key event
5830 if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
5831 this._value( item.value );
5835 // Announce the value in the liveRegion
5836 label = ui.item.attr( "aria-label" ) || item.value;
5837 if ( label && $.trim( label ).length ) {
5838 this.liveRegion.children().hide();
5839 $( "<div>" ).text( label ).appendTo( this.liveRegion );
5842 menuselect: function( event, ui ) {
5843 var item = ui.item.data( "ui-autocomplete-item" ),
5844 previous = this.previous;
5846 // Only trigger when focus was lost (click on menu)
5847 if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) {
5848 this.element.trigger( "focus" );
5849 this.previous = previous;
5851 // #6109 - IE triggers two focus events and the second
5852 // is asynchronous, so we need to reset the previous
5853 // term synchronously and asynchronously :-(
5854 this._delay( function() {
5855 this.previous = previous;
5856 this.selectedItem = item;
5860 if ( false !== this._trigger( "select", event, { item: item } ) ) {
5861 this._value( item.value );
5864 // reset the term after the select event
5865 // this allows custom select handling to work properly
5866 this.term = this._value();
5868 this.close( event );
5869 this.selectedItem = item;
5873 this.liveRegion = $( "<div>", {
5875 "aria-live": "assertive",
5876 "aria-relevant": "additions"
5878 .appendTo( this.document[ 0 ].body );
5880 this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" );
5882 // Turning off autocomplete prevents the browser from remembering the
5883 // value when navigating through history, so we re-enable autocomplete
5884 // if the page is unloaded before the widget is destroyed. #7790
5885 this._on( this.window, {
5886 beforeunload: function() {
5887 this.element.removeAttr( "autocomplete" );
5892 _destroy: function() {
5893 clearTimeout( this.searching );
5894 this.element.removeAttr( "autocomplete" );
5895 this.menu.element.remove();
5896 this.liveRegion.remove();
5899 _setOption: function( key, value ) {
5900 this._super( key, value );
5901 if ( key === "source" ) {
5904 if ( key === "appendTo" ) {
5905 this.menu.element.appendTo( this._appendTo() );
5907 if ( key === "disabled" && value && this.xhr ) {
5912 _isEventTargetInWidget: function( event ) {
5913 var menuElement = this.menu.element[ 0 ];
5915 return event.target === this.element[ 0 ] ||
5916 event.target === menuElement ||
5917 $.contains( menuElement, event.target );
5920 _closeOnClickOutside: function( event ) {
5921 if ( !this._isEventTargetInWidget( event ) ) {
5926 _appendTo: function() {
5927 var element = this.options.appendTo;
5930 element = element.jquery || element.nodeType ?
5932 this.document.find( element ).eq( 0 );
5935 if ( !element || !element[ 0 ] ) {
5936 element = this.element.closest( ".ui-front, dialog" );
5939 if ( !element.length ) {
5940 element = this.document[ 0 ].body;
5946 _initSource: function() {
5949 if ( $.isArray( this.options.source ) ) {
5950 array = this.options.source;
5951 this.source = function( request, response ) {
5952 response( $.ui.autocomplete.filter( array, request.term ) );
5954 } else if ( typeof this.options.source === "string" ) {
5955 url = this.options.source;
5956 this.source = function( request, response ) {
5960 that.xhr = $.ajax( {
5964 success: function( data ) {
5973 this.source = this.options.source;
5977 _searchTimeout: function( event ) {
5978 clearTimeout( this.searching );
5979 this.searching = this._delay( function() {
5981 // Search if the value has changed, or if the user retypes the same value (see #7434)
5982 var equalValues = this.term === this._value(),
5983 menuVisible = this.menu.element.is( ":visible" ),
5984 modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
5986 if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) {
5987 this.selectedItem = null;
5988 this.search( null, event );
5990 }, this.options.delay );
5993 search: function( value, event ) {
5994 value = value != null ? value : this._value();
5996 // Always save the actual value, not the one passed as an argument
5997 this.term = this._value();
5999 if ( value.length < this.options.minLength ) {
6000 return this.close( event );
6003 if ( this._trigger( "search", event ) === false ) {
6007 return this._search( value );
6010 _search: function( value ) {
6012 this._addClass( "ui-autocomplete-loading" );
6013 this.cancelSearch = false;
6015 this.source( { term: value }, this._response() );
6018 _response: function() {
6019 var index = ++this.requestIndex;
6021 return $.proxy( function( content ) {
6022 if ( index === this.requestIndex ) {
6023 this.__response( content );
6027 if ( !this.pending ) {
6028 this._removeClass( "ui-autocomplete-loading" );
6033 __response: function( content ) {
6035 content = this._normalize( content );
6037 this._trigger( "response", null, { content: content } );
6038 if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
6039 this._suggest( content );
6040 this._trigger( "open" );
6043 // use ._close() instead of .close() so we don't cancel future searches
6048 close: function( event ) {
6049 this.cancelSearch = true;
6050 this._close( event );
6053 _close: function( event ) {
6055 // Remove the handler that closes the menu on outside clicks
6056 this._off( this.document, "mousedown" );
6058 if ( this.menu.element.is( ":visible" ) ) {
6059 this.menu.element.hide();
6061 this.isNewMenu = true;
6062 this._trigger( "close", event );
6066 _change: function( event ) {
6067 if ( this.previous !== this._value() ) {
6068 this._trigger( "change", event, { item: this.selectedItem } );
6072 _normalize: function( items ) {
6074 // assume all items have the right format when the first item is complete
6075 if ( items.length && items[ 0 ].label && items[ 0 ].value ) {
6078 return $.map( items, function( item ) {
6079 if ( typeof item === "string" ) {
6085 return $.extend( {}, item, {
6086 label: item.label || item.value,
6087 value: item.value || item.label
6092 _suggest: function( items ) {
6093 var ul = this.menu.element.empty();
6094 this._renderMenu( ul, items );
6095 this.isNewMenu = true;
6096 this.menu.refresh();
6098 // Size and position menu
6101 ul.position( $.extend( {
6103 }, this.options.position ) );
6105 if ( this.options.autoFocus ) {
6109 // Listen for interactions outside of the widget (#6642)
6110 this._on( this.document, {
6111 mousedown: "_closeOnClickOutside"
6115 _resizeMenu: function() {
6116 var ul = this.menu.element;
6117 ul.outerWidth( Math.max(
6119 // Firefox wraps long text (possibly a rounding bug)
6120 // so we add 1px to avoid the wrapping (#7513)
6121 ul.width( "" ).outerWidth() + 1,
6122 this.element.outerWidth()
6126 _renderMenu: function( ul, items ) {
6128 $.each( items, function( index, item ) {
6129 that._renderItemData( ul, item );
6133 _renderItemData: function( ul, item ) {
6134 return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
6137 _renderItem: function( ul, item ) {
6139 .append( $( "<div>" ).text( item.label ) )
6143 _move: function( direction, event ) {
6144 if ( !this.menu.element.is( ":visible" ) ) {
6145 this.search( null, event );
6148 if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
6149 this.menu.isLastItem() && /^next/.test( direction ) ) {
6151 if ( !this.isMultiLine ) {
6152 this._value( this.term );
6158 this.menu[ direction ]( event );
6161 widget: function() {
6162 return this.menu.element;
6165 _value: function() {
6166 return this.valueMethod.apply( this.element, arguments );
6169 _keyEvent: function( keyEvent, event ) {
6170 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
6171 this._move( keyEvent, event );
6173 // Prevents moving cursor to beginning/end of the text field in some browsers
6174 event.preventDefault();
6178 // Support: Chrome <=50
6179 // We should be able to just use this.element.prop( "isContentEditable" )
6180 // but hidden elements always report false in Chrome.
6181 // https://code.google.com/p/chromium/issues/detail?id=313082
6182 _isContentEditable: function( element ) {
6183 if ( !element.length ) {
6187 var editable = element.prop( "contentEditable" );
6189 if ( editable === "inherit" ) {
6190 return this._isContentEditable( element.parent() );
6193 return editable === "true";
6197 $.extend( $.ui.autocomplete, {
6198 escapeRegex: function( value ) {
6199 return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
6201 filter: function( array, term ) {
6202 var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" );
6203 return $.grep( array, function( value ) {
6204 return matcher.test( value.label || value.value || value );
6209 // Live region extension, adding a `messages` option
6210 // NOTE: This is an experimental API. We are still investigating
6211 // a full solution for string manipulation and internationalization.
6212 $.widget( "ui.autocomplete", $.ui.autocomplete, {
6215 noResults: "No search results.",
6216 results: function( amount ) {
6217 return amount + ( amount > 1 ? " results are" : " result is" ) +
6218 " available, use up and down arrow keys to navigate.";
6223 __response: function( content ) {
6225 this._superApply( arguments );
6226 if ( this.options.disabled || this.cancelSearch ) {
6229 if ( content && content.length ) {
6230 message = this.options.messages.results( content.length );
6232 message = this.options.messages.noResults;
6234 this.liveRegion.children().hide();
6235 $( "<div>" ).text( message ).appendTo( this.liveRegion );
6239 var widgetsAutocomplete = $.ui.autocomplete;
6243 * jQuery UI Controlgroup 1.12.1
6244 * http://jqueryui.com
6246 * Copyright jQuery Foundation and other contributors
6247 * Released under the MIT license.
6248 * http://jquery.org/license
6251 //>>label: Controlgroup
6253 //>>description: Visually groups form control widgets
6254 //>>docs: http://api.jqueryui.com/controlgroup/
6255 //>>demos: http://jqueryui.com/controlgroup/
6256 //>>css.structure: ../../themes/base/core.css
6257 //>>css.structure: ../../themes/base/controlgroup.css
6258 //>>css.theme: ../../themes/base/theme.css
6261 var controlgroupCornerRegex = /ui-corner-([a-z]){2,6}/g;
6263 var widgetsControlgroup = $.widget( "ui.controlgroup", {
6265 defaultElement: "<div>",
6267 direction: "horizontal",
6271 "button": "input[type=button], input[type=submit], input[type=reset], button, a",
6272 "controlgroupLabel": ".ui-controlgroup-label",
6273 "checkboxradio": "input[type='checkbox'], input[type='radio']",
6274 "selectmenu": "select",
6275 "spinner": ".ui-spinner-input"
6279 _create: function() {
6283 // To support the enhanced option in jQuery Mobile, we isolate DOM manipulation
6284 _enhance: function() {
6285 this.element.attr( "role", "toolbar" );
6289 _destroy: function() {
6290 this._callChildMethod( "destroy" );
6291 this.childWidgets.removeData( "ui-controlgroup-data" );
6292 this.element.removeAttr( "role" );
6293 if ( this.options.items.controlgroupLabel ) {
6295 .find( this.options.items.controlgroupLabel )
6296 .find( ".ui-controlgroup-label-contents" )
6297 .contents().unwrap();
6301 _initWidgets: function() {
6305 // First we iterate over each of the items options
6306 $.each( this.options.items, function( widget, selector ) {
6310 // Make sure the widget has a selector set
6315 if ( widget === "controlgroupLabel" ) {
6316 labels = that.element.find( selector );
6317 labels.each( function() {
6318 var element = $( this );
6320 if ( element.children( ".ui-controlgroup-label-contents" ).length ) {
6324 .wrapAll( "<span class='ui-controlgroup-label-contents'></span>" );
6326 that._addClass( labels, null, "ui-widget ui-widget-content ui-state-default" );
6327 childWidgets = childWidgets.concat( labels.get() );
6331 // Make sure the widget actually exists
6332 if ( !$.fn[ widget ] ) {
6336 // We assume everything is in the middle to start because we can't determine
6337 // first / last elements until all enhancments are done.
6338 if ( that[ "_" + widget + "Options" ] ) {
6339 options = that[ "_" + widget + "Options" ]( "middle" );
6341 options = { classes: {} };
6344 // Find instances of this widget inside controlgroup and init them
6348 var element = $( this );
6349 var instance = element[ widget ]( "instance" );
6351 // We need to clone the default options for this type of widget to avoid
6352 // polluting the variable options which has a wider scope than a single widget.
6353 var instanceOptions = $.widget.extend( {}, options );
6355 // If the button is the child of a spinner ignore it
6356 // TODO: Find a more generic solution
6357 if ( widget === "button" && element.parent( ".ui-spinner" ).length ) {
6361 // Create the widget if it doesn't exist
6363 instance = element[ widget ]()[ widget ]( "instance" );
6366 instanceOptions.classes =
6367 that._resolveClassesValues( instanceOptions.classes, instance );
6369 element[ widget ]( instanceOptions );
6371 // Store an instance of the controlgroup to be able to reference
6372 // from the outermost element for changing options and refresh
6373 var widgetElement = element[ widget ]( "widget" );
6374 $.data( widgetElement[ 0 ], "ui-controlgroup-data",
6375 instance ? instance : element[ widget ]( "instance" ) );
6377 childWidgets.push( widgetElement[ 0 ] );
6381 this.childWidgets = $( $.unique( childWidgets ) );
6382 this._addClass( this.childWidgets, "ui-controlgroup-item" );
6385 _callChildMethod: function( method ) {
6386 this.childWidgets.each( function() {
6387 var element = $( this ),
6388 data = element.data( "ui-controlgroup-data" );
6389 if ( data && data[ method ] ) {
6395 _updateCornerClass: function( element, position ) {
6396 var remove = "ui-corner-top ui-corner-bottom ui-corner-left ui-corner-right ui-corner-all";
6397 var add = this._buildSimpleOptions( position, "label" ).classes.label;
6399 this._removeClass( element, null, remove );
6400 this._addClass( element, null, add );
6403 _buildSimpleOptions: function( position, key ) {
6404 var direction = this.options.direction === "vertical";
6408 result.classes[ key ] = {
6410 "first": "ui-corner-" + ( direction ? "top" : "left" ),
6411 "last": "ui-corner-" + ( direction ? "bottom" : "right" ),
6412 "only": "ui-corner-all"
6418 _spinnerOptions: function( position ) {
6419 var options = this._buildSimpleOptions( position, "ui-spinner" );
6421 options.classes[ "ui-spinner-up" ] = "";
6422 options.classes[ "ui-spinner-down" ] = "";
6427 _buttonOptions: function( position ) {
6428 return this._buildSimpleOptions( position, "ui-button" );
6431 _checkboxradioOptions: function( position ) {
6432 return this._buildSimpleOptions( position, "ui-checkboxradio-label" );
6435 _selectmenuOptions: function( position ) {
6436 var direction = this.options.direction === "vertical";
6438 width: direction ? "auto" : false,
6441 "ui-selectmenu-button-open": "",
6442 "ui-selectmenu-button-closed": ""
6445 "ui-selectmenu-button-open": "ui-corner-" + ( direction ? "top" : "tl" ),
6446 "ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "top" : "left" )
6449 "ui-selectmenu-button-open": direction ? "" : "ui-corner-tr",
6450 "ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "bottom" : "right" )
6453 "ui-selectmenu-button-open": "ui-corner-top",
6454 "ui-selectmenu-button-closed": "ui-corner-all"
6461 _resolveClassesValues: function( classes, instance ) {
6463 $.each( classes, function( key ) {
6464 var current = instance.options.classes[ key ] || "";
6465 current = $.trim( current.replace( controlgroupCornerRegex, "" ) );
6466 result[ key ] = ( current + " " + classes[ key ] ).replace( /\s+/g, " " );
6471 _setOption: function( key, value ) {
6472 if ( key === "direction" ) {
6473 this._removeClass( "ui-controlgroup-" + this.options.direction );
6476 this._super( key, value );
6477 if ( key === "disabled" ) {
6478 this._callChildMethod( value ? "disable" : "enable" );
6485 refresh: function() {
6489 this._addClass( "ui-controlgroup ui-controlgroup-" + this.options.direction );
6491 if ( this.options.direction === "horizontal" ) {
6492 this._addClass( null, "ui-helper-clearfix" );
6494 this._initWidgets();
6496 children = this.childWidgets;
6498 // We filter here because we need to track all childWidgets not just the visible ones
6499 if ( this.options.onlyVisible ) {
6500 children = children.filter( ":visible" );
6503 if ( children.length ) {
6505 // We do this last because we need to make sure all enhancment is done
6506 // before determining first and last
6507 $.each( [ "first", "last" ], function( index, value ) {
6508 var instance = children[ value ]().data( "ui-controlgroup-data" );
6510 if ( instance && that[ "_" + instance.widgetName + "Options" ] ) {
6511 var options = that[ "_" + instance.widgetName + "Options" ](
6512 children.length === 1 ? "only" : value
6514 options.classes = that._resolveClassesValues( options.classes, instance );
6515 instance.element[ instance.widgetName ]( options );
6517 that._updateCornerClass( children[ value ](), value );
6521 // Finally call the refresh method on each of the child widgets.
6522 this._callChildMethod( "refresh" );
6528 * jQuery UI Checkboxradio 1.12.1
6529 * http://jqueryui.com
6531 * Copyright jQuery Foundation and other contributors
6532 * Released under the MIT license.
6533 * http://jquery.org/license
6536 //>>label: Checkboxradio
6538 //>>description: Enhances a form with multiple themeable checkboxes or radio buttons.
6539 //>>docs: http://api.jqueryui.com/checkboxradio/
6540 //>>demos: http://jqueryui.com/checkboxradio/
6541 //>>css.structure: ../../themes/base/core.css
6542 //>>css.structure: ../../themes/base/button.css
6543 //>>css.structure: ../../themes/base/checkboxradio.css
6544 //>>css.theme: ../../themes/base/theme.css
6548 $.widget( "ui.checkboxradio", [ $.ui.formResetMixin, {
6555 "ui-checkboxradio-label": "ui-corner-all",
6556 "ui-checkboxradio-icon": "ui-corner-all"
6560 _getCreateOptions: function() {
6561 var disabled, labels;
6563 var options = this._super() || {};
6565 // We read the type here, because it makes more sense to throw a element type error first,
6566 // rather then the error for lack of a label. Often if its the wrong type, it
6567 // won't have a label (e.g. calling on a div, btn, etc)
6570 labels = this.element.labels();
6572 // If there are multiple labels, use the last one
6573 this.label = $( labels[ labels.length - 1 ] );
6574 if ( !this.label.length ) {
6575 $.error( "No label found for checkboxradio widget" );
6578 this.originalLabel = "";
6580 // We need to get the label text but this may also need to make sure it does not contain the
6582 this.label.contents().not( this.element[ 0 ] ).each( function() {
6584 // The label contents could be text, html, or a mix. We concat each element to get a
6585 // string representation of the label, without the input as part of it.
6586 that.originalLabel += this.nodeType === 3 ? $( this ).text() : this.outerHTML;
6589 // Set the label option if we found label text
6590 if ( this.originalLabel ) {
6591 options.label = this.originalLabel;
6594 disabled = this.element[ 0 ].disabled;
6595 if ( disabled != null ) {
6596 options.disabled = disabled;
6601 _create: function() {
6602 var checked = this.element[ 0 ].checked;
6604 this._bindFormResetHandler();
6606 if ( this.options.disabled == null ) {
6607 this.options.disabled = this.element[ 0 ].disabled;
6610 this._setOption( "disabled", this.options.disabled );
6611 this._addClass( "ui-checkboxradio", "ui-helper-hidden-accessible" );
6612 this._addClass( this.label, "ui-checkboxradio-label", "ui-button ui-widget" );
6614 if ( this.type === "radio" ) {
6615 this._addClass( this.label, "ui-checkboxradio-radio-label" );
6618 if ( this.options.label && this.options.label !== this.originalLabel ) {
6619 this._updateLabel();
6620 } else if ( this.originalLabel ) {
6621 this.options.label = this.originalLabel;
6627 this._addClass( this.label, "ui-checkboxradio-checked", "ui-state-active" );
6629 this._addClass( this.icon, null, "ui-state-hover" );
6634 change: "_toggleClasses",
6636 this._addClass( this.label, null, "ui-state-focus ui-visual-focus" );
6639 this._removeClass( this.label, null, "ui-state-focus ui-visual-focus" );
6644 _readType: function() {
6645 var nodeName = this.element[ 0 ].nodeName.toLowerCase();
6646 this.type = this.element[ 0 ].type;
6647 if ( nodeName !== "input" || !/radio|checkbox/.test( this.type ) ) {
6648 $.error( "Can't create checkboxradio on element.nodeName=" + nodeName +
6649 " and element.type=" + this.type );
6653 // Support jQuery Mobile enhanced option
6654 _enhance: function() {
6655 this._updateIcon( this.element[ 0 ].checked );
6658 widget: function() {
6662 _getRadioGroup: function() {
6664 var name = this.element[ 0 ].name;
6665 var nameSelector = "input[name='" + $.ui.escapeSelector( name ) + "']";
6671 if ( this.form.length ) {
6672 group = $( this.form[ 0 ].elements ).filter( nameSelector );
6675 // Not inside a form, check all inputs that also are not inside a form
6676 group = $( nameSelector ).filter( function() {
6677 return $( this ).form().length === 0;
6681 return group.not( this.element );
6684 _toggleClasses: function() {
6685 var checked = this.element[ 0 ].checked;
6686 this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked );
6688 if ( this.options.icon && this.type === "checkbox" ) {
6689 this._toggleClass( this.icon, null, "ui-icon-check ui-state-checked", checked )
6690 ._toggleClass( this.icon, null, "ui-icon-blank", !checked );
6693 if ( this.type === "radio" ) {
6694 this._getRadioGroup()
6696 var instance = $( this ).checkboxradio( "instance" );
6699 instance._removeClass( instance.label,
6700 "ui-checkboxradio-checked", "ui-state-active" );
6706 _destroy: function() {
6707 this._unbindFormResetHandler();
6711 this.iconSpace.remove();
6715 _setOption: function( key, value ) {
6717 // We don't allow the value to be set to nothing
6718 if ( key === "label" && !value ) {
6722 this._super( key, value );
6724 if ( key === "disabled" ) {
6725 this._toggleClass( this.label, null, "ui-state-disabled", value );
6726 this.element[ 0 ].disabled = value;
6728 // Don't refresh when setting disabled
6734 _updateIcon: function( checked ) {
6735 var toAdd = "ui-icon ui-icon-background ";
6737 if ( this.options.icon ) {
6739 this.icon = $( "<span>" );
6740 this.iconSpace = $( "<span> </span>" );
6741 this._addClass( this.iconSpace, "ui-checkboxradio-icon-space" );
6744 if ( this.type === "checkbox" ) {
6745 toAdd += checked ? "ui-icon-check ui-state-checked" : "ui-icon-blank";
6746 this._removeClass( this.icon, null, checked ? "ui-icon-blank" : "ui-icon-check" );
6748 toAdd += "ui-icon-blank";
6750 this._addClass( this.icon, "ui-checkboxradio-icon", toAdd );
6752 this._removeClass( this.icon, null, "ui-icon-check ui-state-checked" );
6754 this.icon.prependTo( this.label ).after( this.iconSpace );
6755 } else if ( this.icon !== undefined ) {
6757 this.iconSpace.remove();
6762 _updateLabel: function() {
6764 // Remove the contents of the label ( minus the icon, icon space, and input )
6765 var contents = this.label.contents().not( this.element[ 0 ] );
6767 contents = contents.not( this.icon[ 0 ] );
6769 if ( this.iconSpace ) {
6770 contents = contents.not( this.iconSpace[ 0 ] );
6774 this.label.append( this.options.label );
6777 refresh: function() {
6778 var checked = this.element[ 0 ].checked,
6779 isDisabled = this.element[ 0 ].disabled;
6781 this._updateIcon( checked );
6782 this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked );
6783 if ( this.options.label !== null ) {
6784 this._updateLabel();
6787 if ( isDisabled !== this.options.disabled ) {
6788 this._setOptions( { "disabled": isDisabled } );
6794 var widgetsCheckboxradio = $.ui.checkboxradio;
6798 * jQuery UI Button 1.12.1
6799 * http://jqueryui.com
6801 * Copyright jQuery Foundation and other contributors
6802 * Released under the MIT license.
6803 * http://jquery.org/license
6808 //>>description: Enhances a form with themeable buttons.
6809 //>>docs: http://api.jqueryui.com/button/
6810 //>>demos: http://jqueryui.com/button/
6811 //>>css.structure: ../../themes/base/core.css
6812 //>>css.structure: ../../themes/base/button.css
6813 //>>css.theme: ../../themes/base/theme.css
6817 $.widget( "ui.button", {
6819 defaultElement: "<button>",
6822 "ui-button": "ui-corner-all"
6826 iconPosition: "beginning",
6831 _getCreateOptions: function() {
6834 // This is to support cases like in jQuery Mobile where the base widget does have
6835 // an implementation of _getCreateOptions
6836 options = this._super() || {};
6838 this.isInput = this.element.is( "input" );
6840 disabled = this.element[ 0 ].disabled;
6841 if ( disabled != null ) {
6842 options.disabled = disabled;
6845 this.originalLabel = this.isInput ? this.element.val() : this.element.html();
6846 if ( this.originalLabel ) {
6847 options.label = this.originalLabel;
6853 _create: function() {
6854 if ( !this.option.showLabel & !this.options.icon ) {
6855 this.options.showLabel = true;
6858 // We have to check the option again here even though we did in _getCreateOptions,
6859 // because null may have been passed on init which would override what was set in
6860 // _getCreateOptions
6861 if ( this.options.disabled == null ) {
6862 this.options.disabled = this.element[ 0 ].disabled || false;
6865 this.hasTitle = !!this.element.attr( "title" );
6867 // Check to see if the label needs to be set or if its already correct
6868 if ( this.options.label && this.options.label !== this.originalLabel ) {
6869 if ( this.isInput ) {
6870 this.element.val( this.options.label );
6872 this.element.html( this.options.label );
6875 this._addClass( "ui-button", "ui-widget" );
6876 this._setOption( "disabled", this.options.disabled );
6879 if ( this.element.is( "a" ) ) {
6881 "keyup": function( event ) {
6882 if ( event.keyCode === $.ui.keyCode.SPACE ) {
6883 event.preventDefault();
6885 // Support: PhantomJS <= 1.9, IE 8 Only
6886 // If a native click is available use it so we actually cause navigation
6887 // otherwise just trigger a click event
6888 if ( this.element[ 0 ].click ) {
6889 this.element[ 0 ].click();
6891 this.element.trigger( "click" );
6899 _enhance: function() {
6900 if ( !this.element.is( "button" ) ) {
6901 this.element.attr( "role", "button" );
6904 if ( this.options.icon ) {
6905 this._updateIcon( "icon", this.options.icon );
6906 this._updateTooltip();
6910 _updateTooltip: function() {
6911 this.title = this.element.attr( "title" );
6913 if ( !this.options.showLabel && !this.title ) {
6914 this.element.attr( "title", this.options.label );
6918 _updateIcon: function( option, value ) {
6919 var icon = option !== "iconPosition",
6920 position = icon ? this.options.iconPosition : value,
6921 displayBlock = position === "top" || position === "bottom";
6925 this.icon = $( "<span>" );
6927 this._addClass( this.icon, "ui-button-icon", "ui-icon" );
6929 if ( !this.options.showLabel ) {
6930 this._addClass( "ui-button-icon-only" );
6932 } else if ( icon ) {
6934 // If we are updating the icon remove the old icon class
6935 this._removeClass( this.icon, null, this.options.icon );
6938 // If we are updating the icon add the new icon class
6940 this._addClass( this.icon, null, value );
6943 this._attachIcon( position );
6945 // If the icon is on top or bottom we need to add the ui-widget-icon-block class and remove
6946 // the iconSpace if there is one.
6947 if ( displayBlock ) {
6948 this._addClass( this.icon, null, "ui-widget-icon-block" );
6949 if ( this.iconSpace ) {
6950 this.iconSpace.remove();
6954 // Position is beginning or end so remove the ui-widget-icon-block class and add the
6955 // space if it does not exist
6956 if ( !this.iconSpace ) {
6957 this.iconSpace = $( "<span> </span>" );
6958 this._addClass( this.iconSpace, "ui-button-icon-space" );
6960 this._removeClass( this.icon, null, "ui-wiget-icon-block" );
6961 this._attachIconSpace( position );
6965 _destroy: function() {
6966 this.element.removeAttr( "role" );
6971 if ( this.iconSpace ) {
6972 this.iconSpace.remove();
6974 if ( !this.hasTitle ) {
6975 this.element.removeAttr( "title" );
6979 _attachIconSpace: function( iconPosition ) {
6980 this.icon[ /^(?:end|bottom)/.test( iconPosition ) ? "before" : "after" ]( this.iconSpace );
6983 _attachIcon: function( iconPosition ) {
6984 this.element[ /^(?:end|bottom)/.test( iconPosition ) ? "append" : "prepend" ]( this.icon );
6987 _setOptions: function( options ) {
6988 var newShowLabel = options.showLabel === undefined ?
6989 this.options.showLabel :
6991 newIcon = options.icon === undefined ? this.options.icon : options.icon;
6993 if ( !newShowLabel && !newIcon ) {
6994 options.showLabel = true;
6996 this._super( options );
6999 _setOption: function( key, value ) {
7000 if ( key === "icon" ) {
7002 this._updateIcon( key, value );
7003 } else if ( this.icon ) {
7005 if ( this.iconSpace ) {
7006 this.iconSpace.remove();
7011 if ( key === "iconPosition" ) {
7012 this._updateIcon( key, value );
7015 // Make sure we can't end up with a button that has neither text nor icon
7016 if ( key === "showLabel" ) {
7017 this._toggleClass( "ui-button-icon-only", null, !value );
7018 this._updateTooltip();
7021 if ( key === "label" ) {
7022 if ( this.isInput ) {
7023 this.element.val( value );
7026 // If there is an icon, append it, else nothing then append the value
7027 // this avoids removal of the icon when setting label text
7028 this.element.html( value );
7030 this._attachIcon( this.options.iconPosition );
7031 this._attachIconSpace( this.options.iconPosition );
7036 this._super( key, value );
7038 if ( key === "disabled" ) {
7039 this._toggleClass( null, "ui-state-disabled", value );
7040 this.element[ 0 ].disabled = value;
7042 this.element.blur();
7047 refresh: function() {
7049 // Make sure to only check disabled if its an element that supports this otherwise
7050 // check for the disabled class to determine state
7051 var isDisabled = this.element.is( "input, button" ) ?
7052 this.element[ 0 ].disabled : this.element.hasClass( "ui-button-disabled" );
7054 if ( isDisabled !== this.options.disabled ) {
7055 this._setOptions( { disabled: isDisabled } );
7058 this._updateTooltip();
7063 if ( $.uiBackCompat !== false ) {
7065 // Text and Icons options
7066 $.widget( "ui.button", $.ui.button, {
7075 _create: function() {
7076 if ( this.options.showLabel && !this.options.text ) {
7077 this.options.showLabel = this.options.text;
7079 if ( !this.options.showLabel && this.options.text ) {
7080 this.options.text = this.options.showLabel;
7082 if ( !this.options.icon && ( this.options.icons.primary ||
7083 this.options.icons.secondary ) ) {
7084 if ( this.options.icons.primary ) {
7085 this.options.icon = this.options.icons.primary;
7087 this.options.icon = this.options.icons.secondary;
7088 this.options.iconPosition = "end";
7090 } else if ( this.options.icon ) {
7091 this.options.icons.primary = this.options.icon;
7096 _setOption: function( key, value ) {
7097 if ( key === "text" ) {
7098 this._super( "showLabel", value );
7101 if ( key === "showLabel" ) {
7102 this.options.text = value;
7104 if ( key === "icon" ) {
7105 this.options.icons.primary = value;
7107 if ( key === "icons" ) {
7108 if ( value.primary ) {
7109 this._super( "icon", value.primary );
7110 this._super( "iconPosition", "beginning" );
7111 } else if ( value.secondary ) {
7112 this._super( "icon", value.secondary );
7113 this._super( "iconPosition", "end" );
7116 this._superApply( arguments );
7120 $.fn.button = ( function( orig ) {
7122 if ( !this.length || ( this.length && this[ 0 ].tagName !== "INPUT" ) ||
7123 ( this.length && this[ 0 ].tagName === "INPUT" && (
7124 this.attr( "type" ) !== "checkbox" && this.attr( "type" ) !== "radio"
7126 return orig.apply( this, arguments );
7128 if ( !$.ui.checkboxradio ) {
7129 $.error( "Checkboxradio widget missing" );
7131 if ( arguments.length === 0 ) {
7132 return this.checkboxradio( {
7136 return this.checkboxradio.apply( this, arguments );
7140 $.fn.buttonset = function() {
7141 if ( !$.ui.controlgroup ) {
7142 $.error( "Controlgroup widget missing" );
7144 if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" && arguments[ 2 ] ) {
7145 return this.controlgroup.apply( this,
7146 [ arguments[ 0 ], "items.button", arguments[ 2 ] ] );
7148 if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" ) {
7149 return this.controlgroup.apply( this, [ arguments[ 0 ], "items.button" ] );
7151 if ( typeof arguments[ 0 ] === "object" && arguments[ 0 ].items ) {
7152 arguments[ 0 ].items = {
7153 button: arguments[ 0 ].items
7156 return this.controlgroup.apply( this, arguments );
7160 var widgetsButton = $.ui.button;
7163 // jscs:disable maximumLineLength
7164 /* jscs:disable requireCamelCaseOrUpperCaseIdentifiers */
7166 * jQuery UI Datepicker 1.12.1
7167 * http://jqueryui.com
7169 * Copyright jQuery Foundation and other contributors
7170 * Released under the MIT license.
7171 * http://jquery.org/license
7174 //>>label: Datepicker
7176 //>>description: Displays a calendar from an input or inline for selecting dates.
7177 //>>docs: http://api.jqueryui.com/datepicker/
7178 //>>demos: http://jqueryui.com/datepicker/
7179 //>>css.structure: ../../themes/base/core.css
7180 //>>css.structure: ../../themes/base/datepicker.css
7181 //>>css.theme: ../../themes/base/theme.css
7185 $.extend( $.ui, { datepicker: { version: "1.12.1" } } );
7187 var datepicker_instActive;
7189 function datepicker_getZindex( elem ) {
7190 var position, value;
7191 while ( elem.length && elem[ 0 ] !== document ) {
7193 // Ignore z-index if position is set to a value where z-index is ignored by the browser
7194 // This makes behavior of this function consistent across browsers
7195 // WebKit always returns auto if the element is positioned
7196 position = elem.css( "position" );
7197 if ( position === "absolute" || position === "relative" || position === "fixed" ) {
7199 // IE returns 0 when zIndex is not specified
7200 // other browsers return a string
7201 // we ignore the case of nested elements with an explicit value of 0
7202 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
7203 value = parseInt( elem.css( "zIndex" ), 10 );
7204 if ( !isNaN( value ) && value !== 0 ) {
7208 elem = elem.parent();
7213 /* Date picker manager.
7214 Use the singleton instance of this class, $.datepicker, to interact with the date picker.
7215 Settings for (groups of) date pickers are maintained in an instance object,
7216 allowing multiple different settings on the same page. */
7218 function Datepicker() {
7219 this._curInst = null; // The current instance in use
7220 this._keyEvent = false; // If the last event was a key event
7221 this._disabledInputs = []; // List of date picker inputs that have been disabled
7222 this._datepickerShowing = false; // True if the popup picker is showing , false if not
7223 this._inDialog = false; // True if showing within a "dialog", false if not
7224 this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
7225 this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
7226 this._appendClass = "ui-datepicker-append"; // The name of the append marker class
7227 this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
7228 this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
7229 this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
7230 this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
7231 this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
7232 this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
7233 this.regional = []; // Available regional settings, indexed by language code
7234 this.regional[ "" ] = { // Default regional settings
7235 closeText: "Done", // Display text for close link
7236 prevText: "Prev", // Display text for previous month link
7237 nextText: "Next", // Display text for next month link
7238 currentText: "Today", // Display text for current month link
7239 monthNames: [ "January","February","March","April","May","June",
7240 "July","August","September","October","November","December" ], // Names of months for drop-down and formatting
7241 monthNamesShort: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ], // For formatting
7242 dayNames: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], // For formatting
7243 dayNamesShort: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], // For formatting
7244 dayNamesMin: [ "Su","Mo","Tu","We","Th","Fr","Sa" ], // Column headings for days starting at Sunday
7245 weekHeader: "Wk", // Column header for week of the year
7246 dateFormat: "mm/dd/yy", // See format options on parseDate
7247 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
7248 isRTL: false, // True if right-to-left language, false if left-to-right
7249 showMonthAfterYear: false, // True if the year select precedes month, false for month then year
7250 yearSuffix: "" // Additional text to append to the year in the month headers
7252 this._defaults = { // Global defaults for all the date picker instances
7253 showOn: "focus", // "focus" for popup on focus,
7254 // "button" for trigger button, or "both" for either
7255 showAnim: "fadeIn", // Name of jQuery animation for popup
7256 showOptions: {}, // Options for enhanced animations
7257 defaultDate: null, // Used when field is blank: actual date,
7258 // +/-number for offset from today, null for today
7259 appendText: "", // Display text following the input box, e.g. showing the format
7260 buttonText: "...", // Text for trigger button
7261 buttonImage: "", // URL for trigger button image
7262 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
7263 hideIfNoPrevNext: false, // True to hide next/previous month links
7264 // if not applicable, false to just disable them
7265 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
7266 gotoCurrent: false, // True if today link goes back to current selection instead
7267 changeMonth: false, // True if month can be selected directly, false if only prev/next
7268 changeYear: false, // True if year can be selected directly, false if only prev/next
7269 yearRange: "c-10:c+10", // Range of years to display in drop-down,
7270 // either relative to today's year (-nn:+nn), relative to currently displayed year
7271 // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
7272 showOtherMonths: false, // True to show dates in other months, false to leave blank
7273 selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
7274 showWeek: false, // True to show week of the year, false to not show it
7275 calculateWeek: this.iso8601Week, // How to calculate the week of the year,
7276 // takes a Date and returns the number of the week for it
7277 shortYearCutoff: "+10", // Short year values < this are in the current century,
7278 // > this are in the previous century,
7279 // string value starting with "+" for current year + value
7280 minDate: null, // The earliest selectable date, or null for no limit
7281 maxDate: null, // The latest selectable date, or null for no limit
7282 duration: "fast", // Duration of display/closure
7283 beforeShowDay: null, // Function that takes a date and returns an array with
7284 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
7285 // [2] = cell title (optional), e.g. $.datepicker.noWeekends
7286 beforeShow: null, // Function that takes an input field and
7287 // returns a set of custom settings for the date picker
7288 onSelect: null, // Define a callback function when a date is selected
7289 onChangeMonthYear: null, // Define a callback function when the month or year is changed
7290 onClose: null, // Define a callback function when the datepicker is closed
7291 numberOfMonths: 1, // Number of months to show at a time
7292 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
7293 stepMonths: 1, // Number of months to step back/forward
7294 stepBigMonths: 12, // Number of months to step back/forward for the big links
7295 altField: "", // Selector for an alternate field to store selected dates into
7296 altFormat: "", // The date format to use for the alternate field
7297 constrainInput: true, // The input is constrained by the current date format
7298 showButtonPanel: false, // True to show button panel, false to not show it
7299 autoSize: false, // True to size the input for the date format, false to leave as is
7300 disabled: false // The initial disabled state
7302 $.extend( this._defaults, this.regional[ "" ] );
7303 this.regional.en = $.extend( true, {}, this.regional[ "" ] );
7304 this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en );
7305 this.dpDiv = datepicker_bindHover( $( "<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) );
7308 $.extend( Datepicker.prototype, {
7309 /* Class name added to elements to indicate already configured with a date picker. */
7310 markerClassName: "hasDatepicker",
7312 //Keep track of the maximum number of rows displayed (see #7043)
7315 // TODO rename to "widget" when switching to widget factory
7316 _widgetDatepicker: function() {
7320 /* Override the default settings for all instances of the date picker.
7321 * @param settings object - the new settings to use as defaults (anonymous object)
7322 * @return the manager object
7324 setDefaults: function( settings ) {
7325 datepicker_extendRemove( this._defaults, settings || {} );
7329 /* Attach the date picker to a jQuery selection.
7330 * @param target element - the target input field or division or span
7331 * @param settings object - the new settings to use for this date picker instance (anonymous)
7333 _attachDatepicker: function( target, settings ) {
7334 var nodeName, inline, inst;
7335 nodeName = target.nodeName.toLowerCase();
7336 inline = ( nodeName === "div" || nodeName === "span" );
7339 target.id = "dp" + this.uuid;
7341 inst = this._newInst( $( target ), inline );
7342 inst.settings = $.extend( {}, settings || {} );
7343 if ( nodeName === "input" ) {
7344 this._connectDatepicker( target, inst );
7345 } else if ( inline ) {
7346 this._inlineDatepicker( target, inst );
7350 /* Create a new instance object. */
7351 _newInst: function( target, inline ) {
7352 var id = target[ 0 ].id.replace( /([^A-Za-z0-9_\-])/g, "\\\\$1" ); // escape jQuery meta chars
7353 return { id: id, input: target, // associated target
7354 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
7355 drawMonth: 0, drawYear: 0, // month being drawn
7356 inline: inline, // is datepicker inline or not
7357 dpDiv: ( !inline ? this.dpDiv : // presentation div
7358 datepicker_bindHover( $( "<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) ) ) };
7361 /* Attach the date picker to an input field. */
7362 _connectDatepicker: function( target, inst ) {
7363 var input = $( target );
7364 inst.append = $( [] );
7365 inst.trigger = $( [] );
7366 if ( input.hasClass( this.markerClassName ) ) {
7369 this._attachments( input, inst );
7370 input.addClass( this.markerClassName ).on( "keydown", this._doKeyDown ).
7371 on( "keypress", this._doKeyPress ).on( "keyup", this._doKeyUp );
7372 this._autoSize( inst );
7373 $.data( target, "datepicker", inst );
7375 //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
7376 if ( inst.settings.disabled ) {
7377 this._disableDatepicker( target );
7381 /* Make attachments based on settings. */
7382 _attachments: function( input, inst ) {
7383 var showOn, buttonText, buttonImage,
7384 appendText = this._get( inst, "appendText" ),
7385 isRTL = this._get( inst, "isRTL" );
7387 if ( inst.append ) {
7388 inst.append.remove();
7391 inst.append = $( "<span class='" + this._appendClass + "'>" + appendText + "</span>" );
7392 input[ isRTL ? "before" : "after" ]( inst.append );
7395 input.off( "focus", this._showDatepicker );
7397 if ( inst.trigger ) {
7398 inst.trigger.remove();
7401 showOn = this._get( inst, "showOn" );
7402 if ( showOn === "focus" || showOn === "both" ) { // pop-up date picker when in the marked field
7403 input.on( "focus", this._showDatepicker );
7405 if ( showOn === "button" || showOn === "both" ) { // pop-up date picker when button clicked
7406 buttonText = this._get( inst, "buttonText" );
7407 buttonImage = this._get( inst, "buttonImage" );
7408 inst.trigger = $( this._get( inst, "buttonImageOnly" ) ?
7409 $( "<img/>" ).addClass( this._triggerClass ).
7410 attr( { src: buttonImage, alt: buttonText, title: buttonText } ) :
7411 $( "<button type='button'></button>" ).addClass( this._triggerClass ).
7412 html( !buttonImage ? buttonText : $( "<img/>" ).attr(
7413 { src:buttonImage, alt:buttonText, title:buttonText } ) ) );
7414 input[ isRTL ? "before" : "after" ]( inst.trigger );
7415 inst.trigger.on( "click", function() {
7416 if ( $.datepicker._datepickerShowing && $.datepicker._lastInput === input[ 0 ] ) {
7417 $.datepicker._hideDatepicker();
7418 } else if ( $.datepicker._datepickerShowing && $.datepicker._lastInput !== input[ 0 ] ) {
7419 $.datepicker._hideDatepicker();
7420 $.datepicker._showDatepicker( input[ 0 ] );
7422 $.datepicker._showDatepicker( input[ 0 ] );
7429 /* Apply the maximum length for the date format. */
7430 _autoSize: function( inst ) {
7431 if ( this._get( inst, "autoSize" ) && !inst.inline ) {
7432 var findMax, max, maxI, i,
7433 date = new Date( 2009, 12 - 1, 20 ), // Ensure double digits
7434 dateFormat = this._get( inst, "dateFormat" );
7436 if ( dateFormat.match( /[DM]/ ) ) {
7437 findMax = function( names ) {
7440 for ( i = 0; i < names.length; i++ ) {
7441 if ( names[ i ].length > max ) {
7442 max = names[ i ].length;
7448 date.setMonth( findMax( this._get( inst, ( dateFormat.match( /MM/ ) ?
7449 "monthNames" : "monthNamesShort" ) ) ) );
7450 date.setDate( findMax( this._get( inst, ( dateFormat.match( /DD/ ) ?
7451 "dayNames" : "dayNamesShort" ) ) ) + 20 - date.getDay() );
7453 inst.input.attr( "size", this._formatDate( inst, date ).length );
7457 /* Attach an inline date picker to a div. */
7458 _inlineDatepicker: function( target, inst ) {
7459 var divSpan = $( target );
7460 if ( divSpan.hasClass( this.markerClassName ) ) {
7463 divSpan.addClass( this.markerClassName ).append( inst.dpDiv );
7464 $.data( target, "datepicker", inst );
7465 this._setDate( inst, this._getDefaultDate( inst ), true );
7466 this._updateDatepicker( inst );
7467 this._updateAlternate( inst );
7469 //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
7470 if ( inst.settings.disabled ) {
7471 this._disableDatepicker( target );
7474 // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
7475 // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
7476 inst.dpDiv.css( "display", "block" );
7479 /* Pop-up the date picker in a "dialog" box.
7480 * @param input element - ignored
7481 * @param date string or Date - the initial date to display
7482 * @param onSelect function - the function to call when a date is selected
7483 * @param settings object - update the dialog date picker instance's settings (anonymous object)
7484 * @param pos int[2] - coordinates for the dialog's position within the screen or
7485 * event - with x/y coordinates or
7486 * leave empty for default (screen centre)
7487 * @return the manager object
7489 _dialogDatepicker: function( input, date, onSelect, settings, pos ) {
7490 var id, browserWidth, browserHeight, scrollX, scrollY,
7491 inst = this._dialogInst; // internal instance
7495 id = "dp" + this.uuid;
7496 this._dialogInput = $( "<input type='text' id='" + id +
7497 "' style='position: absolute; top: -100px; width: 0px;'/>" );
7498 this._dialogInput.on( "keydown", this._doKeyDown );
7499 $( "body" ).append( this._dialogInput );
7500 inst = this._dialogInst = this._newInst( this._dialogInput, false );
7502 $.data( this._dialogInput[ 0 ], "datepicker", inst );
7504 datepicker_extendRemove( inst.settings, settings || {} );
7505 date = ( date && date.constructor === Date ? this._formatDate( inst, date ) : date );
7506 this._dialogInput.val( date );
7508 this._pos = ( pos ? ( pos.length ? pos : [ pos.pageX, pos.pageY ] ) : null );
7510 browserWidth = document.documentElement.clientWidth;
7511 browserHeight = document.documentElement.clientHeight;
7512 scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
7513 scrollY = document.documentElement.scrollTop || document.body.scrollTop;
7514 this._pos = // should use actual width/height below
7515 [ ( browserWidth / 2 ) - 100 + scrollX, ( browserHeight / 2 ) - 150 + scrollY ];
7518 // Move input on screen for focus, but hidden behind dialog
7519 this._dialogInput.css( "left", ( this._pos[ 0 ] + 20 ) + "px" ).css( "top", this._pos[ 1 ] + "px" );
7520 inst.settings.onSelect = onSelect;
7521 this._inDialog = true;
7522 this.dpDiv.addClass( this._dialogClass );
7523 this._showDatepicker( this._dialogInput[ 0 ] );
7525 $.blockUI( this.dpDiv );
7527 $.data( this._dialogInput[ 0 ], "datepicker", inst );
7531 /* Detach a datepicker from its control.
7532 * @param target element - the target input field or division or span
7534 _destroyDatepicker: function( target ) {
7536 $target = $( target ),
7537 inst = $.data( target, "datepicker" );
7539 if ( !$target.hasClass( this.markerClassName ) ) {
7543 nodeName = target.nodeName.toLowerCase();
7544 $.removeData( target, "datepicker" );
7545 if ( nodeName === "input" ) {
7546 inst.append.remove();
7547 inst.trigger.remove();
7548 $target.removeClass( this.markerClassName ).
7549 off( "focus", this._showDatepicker ).
7550 off( "keydown", this._doKeyDown ).
7551 off( "keypress", this._doKeyPress ).
7552 off( "keyup", this._doKeyUp );
7553 } else if ( nodeName === "div" || nodeName === "span" ) {
7554 $target.removeClass( this.markerClassName ).empty();
7557 if ( datepicker_instActive === inst ) {
7558 datepicker_instActive = null;
7562 /* Enable the date picker to a jQuery selection.
7563 * @param target element - the target input field or division or span
7565 _enableDatepicker: function( target ) {
7566 var nodeName, inline,
7567 $target = $( target ),
7568 inst = $.data( target, "datepicker" );
7570 if ( !$target.hasClass( this.markerClassName ) ) {
7574 nodeName = target.nodeName.toLowerCase();
7575 if ( nodeName === "input" ) {
7576 target.disabled = false;
7577 inst.trigger.filter( "button" ).
7578 each( function() { this.disabled = false; } ).end().
7579 filter( "img" ).css( { opacity: "1.0", cursor: "" } );
7580 } else if ( nodeName === "div" || nodeName === "span" ) {
7581 inline = $target.children( "." + this._inlineClass );
7582 inline.children().removeClass( "ui-state-disabled" );
7583 inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
7584 prop( "disabled", false );
7586 this._disabledInputs = $.map( this._disabledInputs,
7587 function( value ) { return ( value === target ? null : value ); } ); // delete entry
7590 /* Disable the date picker to a jQuery selection.
7591 * @param target element - the target input field or division or span
7593 _disableDatepicker: function( target ) {
7594 var nodeName, inline,
7595 $target = $( target ),
7596 inst = $.data( target, "datepicker" );
7598 if ( !$target.hasClass( this.markerClassName ) ) {
7602 nodeName = target.nodeName.toLowerCase();
7603 if ( nodeName === "input" ) {
7604 target.disabled = true;
7605 inst.trigger.filter( "button" ).
7606 each( function() { this.disabled = true; } ).end().
7607 filter( "img" ).css( { opacity: "0.5", cursor: "default" } );
7608 } else if ( nodeName === "div" || nodeName === "span" ) {
7609 inline = $target.children( "." + this._inlineClass );
7610 inline.children().addClass( "ui-state-disabled" );
7611 inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
7612 prop( "disabled", true );
7614 this._disabledInputs = $.map( this._disabledInputs,
7615 function( value ) { return ( value === target ? null : value ); } ); // delete entry
7616 this._disabledInputs[ this._disabledInputs.length ] = target;
7619 /* Is the first field in a jQuery collection disabled as a datepicker?
7620 * @param target element - the target input field or division or span
7621 * @return boolean - true if disabled, false if enabled
7623 _isDisabledDatepicker: function( target ) {
7627 for ( var i = 0; i < this._disabledInputs.length; i++ ) {
7628 if ( this._disabledInputs[ i ] === target ) {
7635 /* Retrieve the instance data for the target control.
7636 * @param target element - the target input field or division or span
7637 * @return object - the associated instance data
7638 * @throws error if a jQuery problem getting data
7640 _getInst: function( target ) {
7642 return $.data( target, "datepicker" );
7645 throw "Missing instance data for this datepicker";
7649 /* Update or retrieve the settings for a date picker attached to an input field or division.
7650 * @param target element - the target input field or division or span
7651 * @param name object - the new settings to update or
7652 * string - the name of the setting to change or retrieve,
7653 * when retrieving also "all" for all instance settings or
7654 * "defaults" for all global defaults
7655 * @param value any - the new value for the setting
7656 * (omit if above is an object or to retrieve a value)
7658 _optionDatepicker: function( target, name, value ) {
7659 var settings, date, minDate, maxDate,
7660 inst = this._getInst( target );
7662 if ( arguments.length === 2 && typeof name === "string" ) {
7663 return ( name === "defaults" ? $.extend( {}, $.datepicker._defaults ) :
7664 ( inst ? ( name === "all" ? $.extend( {}, inst.settings ) :
7665 this._get( inst, name ) ) : null ) );
7668 settings = name || {};
7669 if ( typeof name === "string" ) {
7671 settings[ name ] = value;
7675 if ( this._curInst === inst ) {
7676 this._hideDatepicker();
7679 date = this._getDateDatepicker( target, true );
7680 minDate = this._getMinMaxDate( inst, "min" );
7681 maxDate = this._getMinMaxDate( inst, "max" );
7682 datepicker_extendRemove( inst.settings, settings );
7684 // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
7685 if ( minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined ) {
7686 inst.settings.minDate = this._formatDate( inst, minDate );
7688 if ( maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined ) {
7689 inst.settings.maxDate = this._formatDate( inst, maxDate );
7691 if ( "disabled" in settings ) {
7692 if ( settings.disabled ) {
7693 this._disableDatepicker( target );
7695 this._enableDatepicker( target );
7698 this._attachments( $( target ), inst );
7699 this._autoSize( inst );
7700 this._setDate( inst, date );
7701 this._updateAlternate( inst );
7702 this._updateDatepicker( inst );
7706 // Change method deprecated
7707 _changeDatepicker: function( target, name, value ) {
7708 this._optionDatepicker( target, name, value );
7711 /* Redraw the date picker attached to an input field or division.
7712 * @param target element - the target input field or division or span
7714 _refreshDatepicker: function( target ) {
7715 var inst = this._getInst( target );
7717 this._updateDatepicker( inst );
7721 /* Set the dates for a jQuery selection.
7722 * @param target element - the target input field or division or span
7723 * @param date Date - the new date
7725 _setDateDatepicker: function( target, date ) {
7726 var inst = this._getInst( target );
7728 this._setDate( inst, date );
7729 this._updateDatepicker( inst );
7730 this._updateAlternate( inst );
7734 /* Get the date(s) for the first entry in a jQuery selection.
7735 * @param target element - the target input field or division or span
7736 * @param noDefault boolean - true if no default date is to be used
7737 * @return Date - the current date
7739 _getDateDatepicker: function( target, noDefault ) {
7740 var inst = this._getInst( target );
7741 if ( inst && !inst.inline ) {
7742 this._setDateFromField( inst, noDefault );
7744 return ( inst ? this._getDate( inst ) : null );
7747 /* Handle keystrokes. */
7748 _doKeyDown: function( event ) {
7749 var onSelect, dateStr, sel,
7750 inst = $.datepicker._getInst( event.target ),
7752 isRTL = inst.dpDiv.is( ".ui-datepicker-rtl" );
7754 inst._keyEvent = true;
7755 if ( $.datepicker._datepickerShowing ) {
7756 switch ( event.keyCode ) {
7757 case 9: $.datepicker._hideDatepicker();
7759 break; // hide on tab out
7760 case 13: sel = $( "td." + $.datepicker._dayOverClass + ":not(." +
7761 $.datepicker._currentClass + ")", inst.dpDiv );
7763 $.datepicker._selectDay( event.target, inst.selectedMonth, inst.selectedYear, sel[ 0 ] );
7766 onSelect = $.datepicker._get( inst, "onSelect" );
7768 dateStr = $.datepicker._formatDate( inst );
7770 // Trigger custom callback
7771 onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] );
7773 $.datepicker._hideDatepicker();
7776 return false; // don't submit the form
7777 case 27: $.datepicker._hideDatepicker();
7778 break; // hide on escape
7779 case 33: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
7780 -$.datepicker._get( inst, "stepBigMonths" ) :
7781 -$.datepicker._get( inst, "stepMonths" ) ), "M" );
7782 break; // previous month/year on page up/+ ctrl
7783 case 34: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
7784 +$.datepicker._get( inst, "stepBigMonths" ) :
7785 +$.datepicker._get( inst, "stepMonths" ) ), "M" );
7786 break; // next month/year on page down/+ ctrl
7787 case 35: if ( event.ctrlKey || event.metaKey ) {
7788 $.datepicker._clearDate( event.target );
7790 handled = event.ctrlKey || event.metaKey;
7791 break; // clear on ctrl or command +end
7792 case 36: if ( event.ctrlKey || event.metaKey ) {
7793 $.datepicker._gotoToday( event.target );
7795 handled = event.ctrlKey || event.metaKey;
7796 break; // current on ctrl or command +home
7797 case 37: if ( event.ctrlKey || event.metaKey ) {
7798 $.datepicker._adjustDate( event.target, ( isRTL ? +1 : -1 ), "D" );
7800 handled = event.ctrlKey || event.metaKey;
7802 // -1 day on ctrl or command +left
7803 if ( event.originalEvent.altKey ) {
7804 $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
7805 -$.datepicker._get( inst, "stepBigMonths" ) :
7806 -$.datepicker._get( inst, "stepMonths" ) ), "M" );
7809 // next month/year on alt +left on Mac
7811 case 38: if ( event.ctrlKey || event.metaKey ) {
7812 $.datepicker._adjustDate( event.target, -7, "D" );
7814 handled = event.ctrlKey || event.metaKey;
7815 break; // -1 week on ctrl or command +up
7816 case 39: if ( event.ctrlKey || event.metaKey ) {
7817 $.datepicker._adjustDate( event.target, ( isRTL ? -1 : +1 ), "D" );
7819 handled = event.ctrlKey || event.metaKey;
7821 // +1 day on ctrl or command +right
7822 if ( event.originalEvent.altKey ) {
7823 $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
7824 +$.datepicker._get( inst, "stepBigMonths" ) :
7825 +$.datepicker._get( inst, "stepMonths" ) ), "M" );
7828 // next month/year on alt +right
7830 case 40: if ( event.ctrlKey || event.metaKey ) {
7831 $.datepicker._adjustDate( event.target, +7, "D" );
7833 handled = event.ctrlKey || event.metaKey;
7834 break; // +1 week on ctrl or command +down
7835 default: handled = false;
7837 } else if ( event.keyCode === 36 && event.ctrlKey ) { // display the date picker on ctrl+home
7838 $.datepicker._showDatepicker( this );
7844 event.preventDefault();
7845 event.stopPropagation();
7849 /* Filter entered characters - based on date format. */
7850 _doKeyPress: function( event ) {
7852 inst = $.datepicker._getInst( event.target );
7854 if ( $.datepicker._get( inst, "constrainInput" ) ) {
7855 chars = $.datepicker._possibleChars( $.datepicker._get( inst, "dateFormat" ) );
7856 chr = String.fromCharCode( event.charCode == null ? event.keyCode : event.charCode );
7857 return event.ctrlKey || event.metaKey || ( chr < " " || !chars || chars.indexOf( chr ) > -1 );
7861 /* Synchronise manual entry and field/alternate field. */
7862 _doKeyUp: function( event ) {
7864 inst = $.datepicker._getInst( event.target );
7866 if ( inst.input.val() !== inst.lastVal ) {
7868 date = $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
7869 ( inst.input ? inst.input.val() : null ),
7870 $.datepicker._getFormatConfig( inst ) );
7872 if ( date ) { // only if valid
7873 $.datepicker._setDateFromField( inst );
7874 $.datepicker._updateAlternate( inst );
7875 $.datepicker._updateDatepicker( inst );
7884 /* Pop-up the date picker for a given input field.
7885 * If false returned from beforeShow event handler do not show.
7886 * @param input element - the input field attached to the date picker or
7887 * event - if triggered by focus
7889 _showDatepicker: function( input ) {
7890 input = input.target || input;
7891 if ( input.nodeName.toLowerCase() !== "input" ) { // find from button/image trigger
7892 input = $( "input", input.parentNode )[ 0 ];
7895 if ( $.datepicker._isDisabledDatepicker( input ) || $.datepicker._lastInput === input ) { // already here
7899 var inst, beforeShow, beforeShowSettings, isFixed,
7900 offset, showAnim, duration;
7902 inst = $.datepicker._getInst( input );
7903 if ( $.datepicker._curInst && $.datepicker._curInst !== inst ) {
7904 $.datepicker._curInst.dpDiv.stop( true, true );
7905 if ( inst && $.datepicker._datepickerShowing ) {
7906 $.datepicker._hideDatepicker( $.datepicker._curInst.input[ 0 ] );
7910 beforeShow = $.datepicker._get( inst, "beforeShow" );
7911 beforeShowSettings = beforeShow ? beforeShow.apply( input, [ input, inst ] ) : {};
7912 if ( beforeShowSettings === false ) {
7915 datepicker_extendRemove( inst.settings, beforeShowSettings );
7917 inst.lastVal = null;
7918 $.datepicker._lastInput = input;
7919 $.datepicker._setDateFromField( inst );
7921 if ( $.datepicker._inDialog ) { // hide cursor
7924 if ( !$.datepicker._pos ) { // position below input
7925 $.datepicker._pos = $.datepicker._findPos( input );
7926 $.datepicker._pos[ 1 ] += input.offsetHeight; // add the height
7930 $( input ).parents().each( function() {
7931 isFixed |= $( this ).css( "position" ) === "fixed";
7935 offset = { left: $.datepicker._pos[ 0 ], top: $.datepicker._pos[ 1 ] };
7936 $.datepicker._pos = null;
7938 //to avoid flashes on Firefox
7941 // determine sizing offscreen
7942 inst.dpDiv.css( { position: "absolute", display: "block", top: "-1000px" } );
7943 $.datepicker._updateDatepicker( inst );
7945 // fix width for dynamic number of date pickers
7946 // and adjust position before showing
7947 offset = $.datepicker._checkOffset( inst, offset, isFixed );
7948 inst.dpDiv.css( { position: ( $.datepicker._inDialog && $.blockUI ?
7949 "static" : ( isFixed ? "fixed" : "absolute" ) ), display: "none",
7950 left: offset.left + "px", top: offset.top + "px" } );
7952 if ( !inst.inline ) {
7953 showAnim = $.datepicker._get( inst, "showAnim" );
7954 duration = $.datepicker._get( inst, "duration" );
7955 inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 );
7956 $.datepicker._datepickerShowing = true;
7958 if ( $.effects && $.effects.effect[ showAnim ] ) {
7959 inst.dpDiv.show( showAnim, $.datepicker._get( inst, "showOptions" ), duration );
7961 inst.dpDiv[ showAnim || "show" ]( showAnim ? duration : null );
7964 if ( $.datepicker._shouldFocusInput( inst ) ) {
7965 inst.input.trigger( "focus" );
7968 $.datepicker._curInst = inst;
7972 /* Generate the date picker content. */
7973 _updateDatepicker: function( inst ) {
7974 this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
7975 datepicker_instActive = inst; // for delegate hover events
7976 inst.dpDiv.empty().append( this._generateHTML( inst ) );
7977 this._attachHandlers( inst );
7980 numMonths = this._getNumberOfMonths( inst ),
7981 cols = numMonths[ 1 ],
7983 activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" );
7985 if ( activeCell.length > 0 ) {
7986 datepicker_handleMouseover.apply( activeCell.get( 0 ) );
7989 inst.dpDiv.removeClass( "ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4" ).width( "" );
7991 inst.dpDiv.addClass( "ui-datepicker-multi-" + cols ).css( "width", ( width * cols ) + "em" );
7993 inst.dpDiv[ ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ? "add" : "remove" ) +
7994 "Class" ]( "ui-datepicker-multi" );
7995 inst.dpDiv[ ( this._get( inst, "isRTL" ) ? "add" : "remove" ) +
7996 "Class" ]( "ui-datepicker-rtl" );
7998 if ( inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
7999 inst.input.trigger( "focus" );
8002 // Deffered render of the years select (to avoid flashes on Firefox)
8003 if ( inst.yearshtml ) {
8004 origyearshtml = inst.yearshtml;
8005 setTimeout( function() {
8007 //assure that inst.yearshtml didn't change.
8008 if ( origyearshtml === inst.yearshtml && inst.yearshtml ) {
8009 inst.dpDiv.find( "select.ui-datepicker-year:first" ).replaceWith( inst.yearshtml );
8011 origyearshtml = inst.yearshtml = null;
8016 // #6694 - don't focus the input if it's already focused
8017 // this breaks the change event in IE
8018 // Support: IE and jQuery <1.9
8019 _shouldFocusInput: function( inst ) {
8020 return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
8023 /* Check positioning to remain on screen. */
8024 _checkOffset: function( inst, offset, isFixed ) {
8025 var dpWidth = inst.dpDiv.outerWidth(),
8026 dpHeight = inst.dpDiv.outerHeight(),
8027 inputWidth = inst.input ? inst.input.outerWidth() : 0,
8028 inputHeight = inst.input ? inst.input.outerHeight() : 0,
8029 viewWidth = document.documentElement.clientWidth + ( isFixed ? 0 : $( document ).scrollLeft() ),
8030 viewHeight = document.documentElement.clientHeight + ( isFixed ? 0 : $( document ).scrollTop() );
8032 offset.left -= ( this._get( inst, "isRTL" ) ? ( dpWidth - inputWidth ) : 0 );
8033 offset.left -= ( isFixed && offset.left === inst.input.offset().left ) ? $( document ).scrollLeft() : 0;
8034 offset.top -= ( isFixed && offset.top === ( inst.input.offset().top + inputHeight ) ) ? $( document ).scrollTop() : 0;
8036 // Now check if datepicker is showing outside window viewport - move to a better place if so.
8037 offset.left -= Math.min( offset.left, ( offset.left + dpWidth > viewWidth && viewWidth > dpWidth ) ?
8038 Math.abs( offset.left + dpWidth - viewWidth ) : 0 );
8039 offset.top -= Math.min( offset.top, ( offset.top + dpHeight > viewHeight && viewHeight > dpHeight ) ?
8040 Math.abs( dpHeight + inputHeight ) : 0 );
8045 /* Find an object's position on the screen. */
8046 _findPos: function( obj ) {
8048 inst = this._getInst( obj ),
8049 isRTL = this._get( inst, "isRTL" );
8051 while ( obj && ( obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden( obj ) ) ) {
8052 obj = obj[ isRTL ? "previousSibling" : "nextSibling" ];
8055 position = $( obj ).offset();
8056 return [ position.left, position.top ];
8059 /* Hide the date picker from view.
8060 * @param input element - the input field attached to the date picker
8062 _hideDatepicker: function( input ) {
8063 var showAnim, duration, postProcess, onClose,
8064 inst = this._curInst;
8066 if ( !inst || ( input && inst !== $.data( input, "datepicker" ) ) ) {
8070 if ( this._datepickerShowing ) {
8071 showAnim = this._get( inst, "showAnim" );
8072 duration = this._get( inst, "duration" );
8073 postProcess = function() {
8074 $.datepicker._tidyDialog( inst );
8077 // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
8078 if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
8079 inst.dpDiv.hide( showAnim, $.datepicker._get( inst, "showOptions" ), duration, postProcess );
8081 inst.dpDiv[ ( showAnim === "slideDown" ? "slideUp" :
8082 ( showAnim === "fadeIn" ? "fadeOut" : "hide" ) ) ]( ( showAnim ? duration : null ), postProcess );
8088 this._datepickerShowing = false;
8090 onClose = this._get( inst, "onClose" );
8092 onClose.apply( ( inst.input ? inst.input[ 0 ] : null ), [ ( inst.input ? inst.input.val() : "" ), inst ] );
8095 this._lastInput = null;
8096 if ( this._inDialog ) {
8097 this._dialogInput.css( { position: "absolute", left: "0", top: "-100px" } );
8100 $( "body" ).append( this.dpDiv );
8103 this._inDialog = false;
8107 /* Tidy up after a dialog display. */
8108 _tidyDialog: function( inst ) {
8109 inst.dpDiv.removeClass( this._dialogClass ).off( ".ui-datepicker-calendar" );
8112 /* Close date picker if clicked elsewhere. */
8113 _checkExternalClick: function( event ) {
8114 if ( !$.datepicker._curInst ) {
8118 var $target = $( event.target ),
8119 inst = $.datepicker._getInst( $target[ 0 ] );
8121 if ( ( ( $target[ 0 ].id !== $.datepicker._mainDivId &&
8122 $target.parents( "#" + $.datepicker._mainDivId ).length === 0 &&
8123 !$target.hasClass( $.datepicker.markerClassName ) &&
8124 !$target.closest( "." + $.datepicker._triggerClass ).length &&
8125 $.datepicker._datepickerShowing && !( $.datepicker._inDialog && $.blockUI ) ) ) ||
8126 ( $target.hasClass( $.datepicker.markerClassName ) && $.datepicker._curInst !== inst ) ) {
8127 $.datepicker._hideDatepicker();
8131 /* Adjust one of the date sub-fields. */
8132 _adjustDate: function( id, offset, period ) {
8133 var target = $( id ),
8134 inst = this._getInst( target[ 0 ] );
8136 if ( this._isDisabledDatepicker( target[ 0 ] ) ) {
8139 this._adjustInstDate( inst, offset +
8140 ( period === "M" ? this._get( inst, "showCurrentAtPos" ) : 0 ), // undo positioning
8142 this._updateDatepicker( inst );
8145 /* Action for current link. */
8146 _gotoToday: function( id ) {
8149 inst = this._getInst( target[ 0 ] );
8151 if ( this._get( inst, "gotoCurrent" ) && inst.currentDay ) {
8152 inst.selectedDay = inst.currentDay;
8153 inst.drawMonth = inst.selectedMonth = inst.currentMonth;
8154 inst.drawYear = inst.selectedYear = inst.currentYear;
8157 inst.selectedDay = date.getDate();
8158 inst.drawMonth = inst.selectedMonth = date.getMonth();
8159 inst.drawYear = inst.selectedYear = date.getFullYear();
8161 this._notifyChange( inst );
8162 this._adjustDate( target );
8165 /* Action for selecting a new month/year. */
8166 _selectMonthYear: function( id, select, period ) {
8167 var target = $( id ),
8168 inst = this._getInst( target[ 0 ] );
8170 inst[ "selected" + ( period === "M" ? "Month" : "Year" ) ] =
8171 inst[ "draw" + ( period === "M" ? "Month" : "Year" ) ] =
8172 parseInt( select.options[ select.selectedIndex ].value, 10 );
8174 this._notifyChange( inst );
8175 this._adjustDate( target );
8178 /* Action for selecting a day. */
8179 _selectDay: function( id, month, year, td ) {
8183 if ( $( td ).hasClass( this._unselectableClass ) || this._isDisabledDatepicker( target[ 0 ] ) ) {
8187 inst = this._getInst( target[ 0 ] );
8188 inst.selectedDay = inst.currentDay = $( "a", td ).html();
8189 inst.selectedMonth = inst.currentMonth = month;
8190 inst.selectedYear = inst.currentYear = year;
8191 this._selectDate( id, this._formatDate( inst,
8192 inst.currentDay, inst.currentMonth, inst.currentYear ) );
8195 /* Erase the input field and hide the date picker. */
8196 _clearDate: function( id ) {
8197 var target = $( id );
8198 this._selectDate( target, "" );
8201 /* Update the input field with the selected date. */
8202 _selectDate: function( id, dateStr ) {
8205 inst = this._getInst( target[ 0 ] );
8207 dateStr = ( dateStr != null ? dateStr : this._formatDate( inst ) );
8209 inst.input.val( dateStr );
8211 this._updateAlternate( inst );
8213 onSelect = this._get( inst, "onSelect" );
8215 onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] ); // trigger custom callback
8216 } else if ( inst.input ) {
8217 inst.input.trigger( "change" ); // fire the change event
8220 if ( inst.inline ) {
8221 this._updateDatepicker( inst );
8223 this._hideDatepicker();
8224 this._lastInput = inst.input[ 0 ];
8225 if ( typeof( inst.input[ 0 ] ) !== "object" ) {
8226 inst.input.trigger( "focus" ); // restore focus
8228 this._lastInput = null;
8232 /* Update any alternate field to synchronise with the main field. */
8233 _updateAlternate: function( inst ) {
8234 var altFormat, date, dateStr,
8235 altField = this._get( inst, "altField" );
8237 if ( altField ) { // update alternate field too
8238 altFormat = this._get( inst, "altFormat" ) || this._get( inst, "dateFormat" );
8239 date = this._getDate( inst );
8240 dateStr = this.formatDate( altFormat, date, this._getFormatConfig( inst ) );
8241 $( altField ).val( dateStr );
8245 /* Set as beforeShowDay function to prevent selection of weekends.
8246 * @param date Date - the date to customise
8247 * @return [boolean, string] - is this date selectable?, what is its CSS class?
8249 noWeekends: function( date ) {
8250 var day = date.getDay();
8251 return [ ( day > 0 && day < 6 ), "" ];
8254 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
8255 * @param date Date - the date to get the week for
8256 * @return number - the number of the week within the year that contains this date
8258 iso8601Week: function( date ) {
8260 checkDate = new Date( date.getTime() );
8262 // Find Thursday of this week starting on Monday
8263 checkDate.setDate( checkDate.getDate() + 4 - ( checkDate.getDay() || 7 ) );
8265 time = checkDate.getTime();
8266 checkDate.setMonth( 0 ); // Compare with Jan 1
8267 checkDate.setDate( 1 );
8268 return Math.floor( Math.round( ( time - checkDate ) / 86400000 ) / 7 ) + 1;
8271 /* Parse a string value into a date object.
8272 * See formatDate below for the possible formats.
8274 * @param format string - the expected format of the date
8275 * @param value string - the date in the above format
8276 * @param settings Object - attributes include:
8277 * shortYearCutoff number - the cutoff year for determining the century (optional)
8278 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
8279 * dayNames string[7] - names of the days from Sunday (optional)
8280 * monthNamesShort string[12] - abbreviated names of the months (optional)
8281 * monthNames string[12] - names of the months (optional)
8282 * @return Date - the extracted date value or null if value is blank
8284 parseDate: function( format, value, settings ) {
8285 if ( format == null || value == null ) {
8286 throw "Invalid arguments";
8289 value = ( typeof value === "object" ? value.toString() : value + "" );
8290 if ( value === "" ) {
8294 var iFormat, dim, extra,
8296 shortYearCutoffTemp = ( settings ? settings.shortYearCutoff : null ) || this._defaults.shortYearCutoff,
8297 shortYearCutoff = ( typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
8298 new Date().getFullYear() % 100 + parseInt( shortYearCutoffTemp, 10 ) ),
8299 dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
8300 dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
8301 monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
8302 monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,
8310 // Check whether a format character is doubled
8311 lookAhead = function( match ) {
8312 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
8319 // Extract a number from the string value
8320 getNumber = function( match ) {
8321 var isDoubled = lookAhead( match ),
8322 size = ( match === "@" ? 14 : ( match === "!" ? 20 :
8323 ( match === "y" && isDoubled ? 4 : ( match === "o" ? 3 : 2 ) ) ) ),
8324 minSize = ( match === "y" ? size : 1 ),
8325 digits = new RegExp( "^\\d{" + minSize + "," + size + "}" ),
8326 num = value.substring( iValue ).match( digits );
8328 throw "Missing number at position " + iValue;
8330 iValue += num[ 0 ].length;
8331 return parseInt( num[ 0 ], 10 );
8334 // Extract a name from the string value and convert to an index
8335 getName = function( match, shortNames, longNames ) {
8337 names = $.map( lookAhead( match ) ? longNames : shortNames, function( v, k ) {
8338 return [ [ k, v ] ];
8339 } ).sort( function( a, b ) {
8340 return -( a[ 1 ].length - b[ 1 ].length );
8343 $.each( names, function( i, pair ) {
8344 var name = pair[ 1 ];
8345 if ( value.substr( iValue, name.length ).toLowerCase() === name.toLowerCase() ) {
8347 iValue += name.length;
8351 if ( index !== -1 ) {
8354 throw "Unknown name at position " + iValue;
8358 // Confirm that a literal character matches the string value
8359 checkLiteral = function() {
8360 if ( value.charAt( iValue ) !== format.charAt( iFormat ) ) {
8361 throw "Unexpected literal at position " + iValue;
8366 for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
8368 if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
8374 switch ( format.charAt( iFormat ) ) {
8376 day = getNumber( "d" );
8379 getName( "D", dayNamesShort, dayNames );
8382 doy = getNumber( "o" );
8385 month = getNumber( "m" );
8388 month = getName( "M", monthNamesShort, monthNames );
8391 year = getNumber( "y" );
8394 date = new Date( getNumber( "@" ) );
8395 year = date.getFullYear();
8396 month = date.getMonth() + 1;
8397 day = date.getDate();
8400 date = new Date( ( getNumber( "!" ) - this._ticksTo1970 ) / 10000 );
8401 year = date.getFullYear();
8402 month = date.getMonth() + 1;
8403 day = date.getDate();
8406 if ( lookAhead( "'" ) ) {
8418 if ( iValue < value.length ) {
8419 extra = value.substr( iValue );
8420 if ( !/^\s+/.test( extra ) ) {
8421 throw "Extra/unparsed characters found in date: " + extra;
8425 if ( year === -1 ) {
8426 year = new Date().getFullYear();
8427 } else if ( year < 100 ) {
8428 year += new Date().getFullYear() - new Date().getFullYear() % 100 +
8429 ( year <= shortYearCutoff ? 0 : -100 );
8436 dim = this._getDaysInMonth( year, month - 1 );
8445 date = this._daylightSavingAdjust( new Date( year, month - 1, day ) );
8446 if ( date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day ) {
8447 throw "Invalid date"; // E.g. 31/02/00
8452 /* Standard date formats. */
8453 ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
8454 COOKIE: "D, dd M yy",
8455 ISO_8601: "yy-mm-dd",
8456 RFC_822: "D, d M y",
8457 RFC_850: "DD, dd-M-y",
8458 RFC_1036: "D, d M y",
8459 RFC_1123: "D, d M yy",
8460 RFC_2822: "D, d M yy",
8461 RSS: "D, d M y", // RFC 822
8464 W3C: "yy-mm-dd", // ISO 8601
8466 _ticksTo1970: ( ( ( 1970 - 1 ) * 365 + Math.floor( 1970 / 4 ) - Math.floor( 1970 / 100 ) +
8467 Math.floor( 1970 / 400 ) ) * 24 * 60 * 60 * 10000000 ),
8469 /* Format a date object into a string value.
8470 * The format can be combinations of the following:
8471 * d - day of month (no leading zero)
8472 * dd - day of month (two digit)
8473 * o - day of year (no leading zeros)
8474 * oo - day of year (three digit)
8475 * D - day name short
8476 * DD - day name long
8477 * m - month of year (no leading zero)
8478 * mm - month of year (two digit)
8479 * M - month name short
8480 * MM - month name long
8481 * y - year (two digit)
8482 * yy - year (four digit)
8483 * @ - Unix timestamp (ms since 01/01/1970)
8484 * ! - Windows ticks (100ns since 01/01/0001)
8485 * "..." - literal text
8488 * @param format string - the desired format of the date
8489 * @param date Date - the date value to format
8490 * @param settings Object - attributes include:
8491 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
8492 * dayNames string[7] - names of the days from Sunday (optional)
8493 * monthNamesShort string[12] - abbreviated names of the months (optional)
8494 * monthNames string[12] - names of the months (optional)
8495 * @return string - the date in the above format
8497 formatDate: function( format, date, settings ) {
8503 dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
8504 dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
8505 monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
8506 monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,
8508 // Check whether a format character is doubled
8509 lookAhead = function( match ) {
8510 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
8517 // Format a number, with leading zero if necessary
8518 formatNumber = function( match, value, len ) {
8519 var num = "" + value;
8520 if ( lookAhead( match ) ) {
8521 while ( num.length < len ) {
8528 // Format a name, short or long as requested
8529 formatName = function( match, value, shortNames, longNames ) {
8530 return ( lookAhead( match ) ? longNames[ value ] : shortNames[ value ] );
8536 for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
8538 if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
8541 output += format.charAt( iFormat );
8544 switch ( format.charAt( iFormat ) ) {
8546 output += formatNumber( "d", date.getDate(), 2 );
8549 output += formatName( "D", date.getDay(), dayNamesShort, dayNames );
8552 output += formatNumber( "o",
8553 Math.round( ( new Date( date.getFullYear(), date.getMonth(), date.getDate() ).getTime() - new Date( date.getFullYear(), 0, 0 ).getTime() ) / 86400000 ), 3 );
8556 output += formatNumber( "m", date.getMonth() + 1, 2 );
8559 output += formatName( "M", date.getMonth(), monthNamesShort, monthNames );
8562 output += ( lookAhead( "y" ) ? date.getFullYear() :
8563 ( date.getFullYear() % 100 < 10 ? "0" : "" ) + date.getFullYear() % 100 );
8566 output += date.getTime();
8569 output += date.getTime() * 10000 + this._ticksTo1970;
8572 if ( lookAhead( "'" ) ) {
8579 output += format.charAt( iFormat );
8587 /* Extract all possible characters from the date format. */
8588 _possibleChars: function( format ) {
8593 // Check whether a format character is doubled
8594 lookAhead = function( match ) {
8595 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
8602 for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
8604 if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
8607 chars += format.charAt( iFormat );
8610 switch ( format.charAt( iFormat ) ) {
8611 case "d": case "m": case "y": case "@":
8612 chars += "0123456789";
8615 return null; // Accept anything
8617 if ( lookAhead( "'" ) ) {
8624 chars += format.charAt( iFormat );
8631 /* Get a setting value, defaulting if necessary. */
8632 _get: function( inst, name ) {
8633 return inst.settings[ name ] !== undefined ?
8634 inst.settings[ name ] : this._defaults[ name ];
8637 /* Parse existing date and initialise date picker. */
8638 _setDateFromField: function( inst, noDefault ) {
8639 if ( inst.input.val() === inst.lastVal ) {
8643 var dateFormat = this._get( inst, "dateFormat" ),
8644 dates = inst.lastVal = inst.input ? inst.input.val() : null,
8645 defaultDate = this._getDefaultDate( inst ),
8647 settings = this._getFormatConfig( inst );
8650 date = this.parseDate( dateFormat, dates, settings ) || defaultDate;
8652 dates = ( noDefault ? "" : dates );
8654 inst.selectedDay = date.getDate();
8655 inst.drawMonth = inst.selectedMonth = date.getMonth();
8656 inst.drawYear = inst.selectedYear = date.getFullYear();
8657 inst.currentDay = ( dates ? date.getDate() : 0 );
8658 inst.currentMonth = ( dates ? date.getMonth() : 0 );
8659 inst.currentYear = ( dates ? date.getFullYear() : 0 );
8660 this._adjustInstDate( inst );
8663 /* Retrieve the default date shown on opening. */
8664 _getDefaultDate: function( inst ) {
8665 return this._restrictMinMax( inst,
8666 this._determineDate( inst, this._get( inst, "defaultDate" ), new Date() ) );
8669 /* A date may be specified as an exact value or a relative one. */
8670 _determineDate: function( inst, date, defaultDate ) {
8671 var offsetNumeric = function( offset ) {
8672 var date = new Date();
8673 date.setDate( date.getDate() + offset );
8676 offsetString = function( offset ) {
8678 return $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
8679 offset, $.datepicker._getFormatConfig( inst ) );
8686 var date = ( offset.toLowerCase().match( /^c/ ) ?
8687 $.datepicker._getDate( inst ) : null ) || new Date(),
8688 year = date.getFullYear(),
8689 month = date.getMonth(),
8690 day = date.getDate(),
8691 pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
8692 matches = pattern.exec( offset );
8695 switch ( matches[ 2 ] || "d" ) {
8696 case "d" : case "D" :
8697 day += parseInt( matches[ 1 ], 10 ); break;
8698 case "w" : case "W" :
8699 day += parseInt( matches[ 1 ], 10 ) * 7; break;
8700 case "m" : case "M" :
8701 month += parseInt( matches[ 1 ], 10 );
8702 day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
8704 case "y": case "Y" :
8705 year += parseInt( matches[ 1 ], 10 );
8706 day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
8709 matches = pattern.exec( offset );
8711 return new Date( year, month, day );
8713 newDate = ( date == null || date === "" ? defaultDate : ( typeof date === "string" ? offsetString( date ) :
8714 ( typeof date === "number" ? ( isNaN( date ) ? defaultDate : offsetNumeric( date ) ) : new Date( date.getTime() ) ) ) );
8716 newDate = ( newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate );
8718 newDate.setHours( 0 );
8719 newDate.setMinutes( 0 );
8720 newDate.setSeconds( 0 );
8721 newDate.setMilliseconds( 0 );
8723 return this._daylightSavingAdjust( newDate );
8726 /* Handle switch to/from daylight saving.
8727 * Hours may be non-zero on daylight saving cut-over:
8728 * > 12 when midnight changeover, but then cannot generate
8729 * midnight datetime, so jump to 1AM, otherwise reset.
8730 * @param date (Date) the date to check
8731 * @return (Date) the corrected date
8733 _daylightSavingAdjust: function( date ) {
8737 date.setHours( date.getHours() > 12 ? date.getHours() + 2 : 0 );
8741 /* Set the date(s) directly. */
8742 _setDate: function( inst, date, noChange ) {
8744 origMonth = inst.selectedMonth,
8745 origYear = inst.selectedYear,
8746 newDate = this._restrictMinMax( inst, this._determineDate( inst, date, new Date() ) );
8748 inst.selectedDay = inst.currentDay = newDate.getDate();
8749 inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
8750 inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
8751 if ( ( origMonth !== inst.selectedMonth || origYear !== inst.selectedYear ) && !noChange ) {
8752 this._notifyChange( inst );
8754 this._adjustInstDate( inst );
8756 inst.input.val( clear ? "" : this._formatDate( inst ) );
8760 /* Retrieve the date(s) directly. */
8761 _getDate: function( inst ) {
8762 var startDate = ( !inst.currentYear || ( inst.input && inst.input.val() === "" ) ? null :
8763 this._daylightSavingAdjust( new Date(
8764 inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
8768 /* Attach the onxxx handlers. These are declared statically so
8769 * they work with static code transformers like Caja.
8771 _attachHandlers: function( inst ) {
8772 var stepMonths = this._get( inst, "stepMonths" ),
8773 id = "#" + inst.id.replace( /\\\\/g, "\\" );
8774 inst.dpDiv.find( "[data-handler]" ).map( function() {
8777 $.datepicker._adjustDate( id, -stepMonths, "M" );
8780 $.datepicker._adjustDate( id, +stepMonths, "M" );
8783 $.datepicker._hideDatepicker();
8786 $.datepicker._gotoToday( id );
8788 selectDay: function() {
8789 $.datepicker._selectDay( id, +this.getAttribute( "data-month" ), +this.getAttribute( "data-year" ), this );
8792 selectMonth: function() {
8793 $.datepicker._selectMonthYear( id, this, "M" );
8796 selectYear: function() {
8797 $.datepicker._selectMonthYear( id, this, "Y" );
8801 $( this ).on( this.getAttribute( "data-event" ), handler[ this.getAttribute( "data-handler" ) ] );
8805 /* Generate the HTML for the current state of the date picker. */
8806 _generateHTML: function( inst ) {
8807 var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
8808 controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
8809 monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
8810 selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
8811 cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
8812 printDate, dRow, tbody, daySettings, otherMonth, unselectable,
8813 tempDate = new Date(),
8814 today = this._daylightSavingAdjust(
8815 new Date( tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate() ) ), // clear time
8816 isRTL = this._get( inst, "isRTL" ),
8817 showButtonPanel = this._get( inst, "showButtonPanel" ),
8818 hideIfNoPrevNext = this._get( inst, "hideIfNoPrevNext" ),
8819 navigationAsDateFormat = this._get( inst, "navigationAsDateFormat" ),
8820 numMonths = this._getNumberOfMonths( inst ),
8821 showCurrentAtPos = this._get( inst, "showCurrentAtPos" ),
8822 stepMonths = this._get( inst, "stepMonths" ),
8823 isMultiMonth = ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ),
8824 currentDate = this._daylightSavingAdjust( ( !inst.currentDay ? new Date( 9999, 9, 9 ) :
8825 new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) ),
8826 minDate = this._getMinMaxDate( inst, "min" ),
8827 maxDate = this._getMinMaxDate( inst, "max" ),
8828 drawMonth = inst.drawMonth - showCurrentAtPos,
8829 drawYear = inst.drawYear;
8831 if ( drawMonth < 0 ) {
8836 maxDraw = this._daylightSavingAdjust( new Date( maxDate.getFullYear(),
8837 maxDate.getMonth() - ( numMonths[ 0 ] * numMonths[ 1 ] ) + 1, maxDate.getDate() ) );
8838 maxDraw = ( minDate && maxDraw < minDate ? minDate : maxDraw );
8839 while ( this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 ) ) > maxDraw ) {
8841 if ( drawMonth < 0 ) {
8847 inst.drawMonth = drawMonth;
8848 inst.drawYear = drawYear;
8850 prevText = this._get( inst, "prevText" );
8851 prevText = ( !navigationAsDateFormat ? prevText : this.formatDate( prevText,
8852 this._daylightSavingAdjust( new Date( drawYear, drawMonth - stepMonths, 1 ) ),
8853 this._getFormatConfig( inst ) ) );
8855 prev = ( this._canAdjustMonth( inst, -1, drawYear, drawMonth ) ?
8856 "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
8857 " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w" ) + "'>" + prevText + "</span></a>" :
8858 ( hideIfNoPrevNext ? "" : "<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w" ) + "'>" + prevText + "</span></a>" ) );
8860 nextText = this._get( inst, "nextText" );
8861 nextText = ( !navigationAsDateFormat ? nextText : this.formatDate( nextText,
8862 this._daylightSavingAdjust( new Date( drawYear, drawMonth + stepMonths, 1 ) ),
8863 this._getFormatConfig( inst ) ) );
8865 next = ( this._canAdjustMonth( inst, +1, drawYear, drawMonth ) ?
8866 "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
8867 " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e" ) + "'>" + nextText + "</span></a>" :
8868 ( hideIfNoPrevNext ? "" : "<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e" ) + "'>" + nextText + "</span></a>" ) );
8870 currentText = this._get( inst, "currentText" );
8871 gotoDate = ( this._get( inst, "gotoCurrent" ) && inst.currentDay ? currentDate : today );
8872 currentText = ( !navigationAsDateFormat ? currentText :
8873 this.formatDate( currentText, gotoDate, this._getFormatConfig( inst ) ) );
8875 controls = ( !inst.inline ? "<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>" +
8876 this._get( inst, "closeText" ) + "</button>" : "" );
8878 buttonPanel = ( showButtonPanel ) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + ( isRTL ? controls : "" ) +
8879 ( this._isInRange( inst, gotoDate ) ? "<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'" +
8880 ">" + currentText + "</button>" : "" ) + ( isRTL ? "" : controls ) + "</div>" : "";
8882 firstDay = parseInt( this._get( inst, "firstDay" ), 10 );
8883 firstDay = ( isNaN( firstDay ) ? 0 : firstDay );
8885 showWeek = this._get( inst, "showWeek" );
8886 dayNames = this._get( inst, "dayNames" );
8887 dayNamesMin = this._get( inst, "dayNamesMin" );
8888 monthNames = this._get( inst, "monthNames" );
8889 monthNamesShort = this._get( inst, "monthNamesShort" );
8890 beforeShowDay = this._get( inst, "beforeShowDay" );
8891 showOtherMonths = this._get( inst, "showOtherMonths" );
8892 selectOtherMonths = this._get( inst, "selectOtherMonths" );
8893 defaultDate = this._getDefaultDate( inst );
8896 for ( row = 0; row < numMonths[ 0 ]; row++ ) {
8899 for ( col = 0; col < numMonths[ 1 ]; col++ ) {
8900 selectedDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, inst.selectedDay ) );
8901 cornerClass = " ui-corner-all";
8903 if ( isMultiMonth ) {
8904 calender += "<div class='ui-datepicker-group";
8905 if ( numMonths[ 1 ] > 1 ) {
8907 case 0: calender += " ui-datepicker-group-first";
8908 cornerClass = " ui-corner-" + ( isRTL ? "right" : "left" ); break;
8909 case numMonths[ 1 ] - 1: calender += " ui-datepicker-group-last";
8910 cornerClass = " ui-corner-" + ( isRTL ? "left" : "right" ); break;
8911 default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
8916 calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
8917 ( /all|left/.test( cornerClass ) && row === 0 ? ( isRTL ? next : prev ) : "" ) +
8918 ( /all|right/.test( cornerClass ) && row === 0 ? ( isRTL ? prev : next ) : "" ) +
8919 this._generateMonthYearHeader( inst, drawMonth, drawYear, minDate, maxDate,
8920 row > 0 || col > 0, monthNames, monthNamesShort ) + // draw month headers
8921 "</div><table class='ui-datepicker-calendar'><thead>" +
8923 thead = ( showWeek ? "<th class='ui-datepicker-week-col'>" + this._get( inst, "weekHeader" ) + "</th>" : "" );
8924 for ( dow = 0; dow < 7; dow++ ) { // days of the week
8925 day = ( dow + firstDay ) % 7;
8926 thead += "<th scope='col'" + ( ( dow + firstDay + 6 ) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "" ) + ">" +
8927 "<span title='" + dayNames[ day ] + "'>" + dayNamesMin[ day ] + "</span></th>";
8929 calender += thead + "</tr></thead><tbody>";
8930 daysInMonth = this._getDaysInMonth( drawYear, drawMonth );
8931 if ( drawYear === inst.selectedYear && drawMonth === inst.selectedMonth ) {
8932 inst.selectedDay = Math.min( inst.selectedDay, daysInMonth );
8934 leadDays = ( this._getFirstDayOfMonth( drawYear, drawMonth ) - firstDay + 7 ) % 7;
8935 curRows = Math.ceil( ( leadDays + daysInMonth ) / 7 ); // calculate the number of rows to generate
8936 numRows = ( isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows ); //If multiple months, use the higher number of rows (see #7043)
8937 this.maxRows = numRows;
8938 printDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 - leadDays ) );
8939 for ( dRow = 0; dRow < numRows; dRow++ ) { // create date picker rows
8941 tbody = ( !showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
8942 this._get( inst, "calculateWeek" )( printDate ) + "</td>" );
8943 for ( dow = 0; dow < 7; dow++ ) { // create date picker days
8944 daySettings = ( beforeShowDay ?
8945 beforeShowDay.apply( ( inst.input ? inst.input[ 0 ] : null ), [ printDate ] ) : [ true, "" ] );
8946 otherMonth = ( printDate.getMonth() !== drawMonth );
8947 unselectable = ( otherMonth && !selectOtherMonths ) || !daySettings[ 0 ] ||
8948 ( minDate && printDate < minDate ) || ( maxDate && printDate > maxDate );
8949 tbody += "<td class='" +
8950 ( ( dow + firstDay + 6 ) % 7 >= 5 ? " ui-datepicker-week-end" : "" ) + // highlight weekends
8951 ( otherMonth ? " ui-datepicker-other-month" : "" ) + // highlight days from other months
8952 ( ( printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent ) || // user pressed key
8953 ( defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime() ) ?
8955 // or defaultDate is current printedDate and defaultDate is selectedDate
8956 " " + this._dayOverClass : "" ) + // highlight selected day
8957 ( unselectable ? " " + this._unselectableClass + " ui-state-disabled" : "" ) + // highlight unselectable days
8958 ( otherMonth && !showOtherMonths ? "" : " " + daySettings[ 1 ] + // highlight custom dates
8959 ( printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "" ) + // highlight selected day
8960 ( printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "" ) ) + "'" + // highlight today (if different)
8961 ( ( !otherMonth || showOtherMonths ) && daySettings[ 2 ] ? " title='" + daySettings[ 2 ].replace( /'/g, "'" ) + "'" : "" ) + // cell title
8962 ( unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'" ) + ">" + // actions
8963 ( otherMonth && !showOtherMonths ? " " : // display for other months
8964 ( unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
8965 ( printDate.getTime() === today.getTime() ? " ui-state-highlight" : "" ) +
8966 ( printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "" ) + // highlight selected day
8967 ( otherMonth ? " ui-priority-secondary" : "" ) + // distinguish dates from other months
8968 "' href='#'>" + printDate.getDate() + "</a>" ) ) + "</td>"; // display selectable date
8969 printDate.setDate( printDate.getDate() + 1 );
8970 printDate = this._daylightSavingAdjust( printDate );
8972 calender += tbody + "</tr>";
8975 if ( drawMonth > 11 ) {
8979 calender += "</tbody></table>" + ( isMultiMonth ? "</div>" +
8980 ( ( numMonths[ 0 ] > 0 && col === numMonths[ 1 ] - 1 ) ? "<div class='ui-datepicker-row-break'></div>" : "" ) : "" );
8985 html += buttonPanel;
8986 inst._keyEvent = false;
8990 /* Generate the month and year header. */
8991 _generateMonthYearHeader: function( inst, drawMonth, drawYear, minDate, maxDate,
8992 secondary, monthNames, monthNamesShort ) {
8994 var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
8995 changeMonth = this._get( inst, "changeMonth" ),
8996 changeYear = this._get( inst, "changeYear" ),
8997 showMonthAfterYear = this._get( inst, "showMonthAfterYear" ),
8998 html = "<div class='ui-datepicker-title'>",
9002 if ( secondary || !changeMonth ) {
9003 monthHtml += "<span class='ui-datepicker-month'>" + monthNames[ drawMonth ] + "</span>";
9005 inMinYear = ( minDate && minDate.getFullYear() === drawYear );
9006 inMaxYear = ( maxDate && maxDate.getFullYear() === drawYear );
9007 monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
9008 for ( month = 0; month < 12; month++ ) {
9009 if ( ( !inMinYear || month >= minDate.getMonth() ) && ( !inMaxYear || month <= maxDate.getMonth() ) ) {
9010 monthHtml += "<option value='" + month + "'" +
9011 ( month === drawMonth ? " selected='selected'" : "" ) +
9012 ">" + monthNamesShort[ month ] + "</option>";
9015 monthHtml += "</select>";
9018 if ( !showMonthAfterYear ) {
9019 html += monthHtml + ( secondary || !( changeMonth && changeYear ) ? " " : "" );
9023 if ( !inst.yearshtml ) {
9024 inst.yearshtml = "";
9025 if ( secondary || !changeYear ) {
9026 html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
9029 // determine range of years to display
9030 years = this._get( inst, "yearRange" ).split( ":" );
9031 thisYear = new Date().getFullYear();
9032 determineYear = function( value ) {
9033 var year = ( value.match( /c[+\-].*/ ) ? drawYear + parseInt( value.substring( 1 ), 10 ) :
9034 ( value.match( /[+\-].*/ ) ? thisYear + parseInt( value, 10 ) :
9035 parseInt( value, 10 ) ) );
9036 return ( isNaN( year ) ? thisYear : year );
9038 year = determineYear( years[ 0 ] );
9039 endYear = Math.max( year, determineYear( years[ 1 ] || "" ) );
9040 year = ( minDate ? Math.max( year, minDate.getFullYear() ) : year );
9041 endYear = ( maxDate ? Math.min( endYear, maxDate.getFullYear() ) : endYear );
9042 inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
9043 for ( ; year <= endYear; year++ ) {
9044 inst.yearshtml += "<option value='" + year + "'" +
9045 ( year === drawYear ? " selected='selected'" : "" ) +
9046 ">" + year + "</option>";
9048 inst.yearshtml += "</select>";
9050 html += inst.yearshtml;
9051 inst.yearshtml = null;
9055 html += this._get( inst, "yearSuffix" );
9056 if ( showMonthAfterYear ) {
9057 html += ( secondary || !( changeMonth && changeYear ) ? " " : "" ) + monthHtml;
9059 html += "</div>"; // Close datepicker_header
9063 /* Adjust one of the date sub-fields. */
9064 _adjustInstDate: function( inst, offset, period ) {
9065 var year = inst.selectedYear + ( period === "Y" ? offset : 0 ),
9066 month = inst.selectedMonth + ( period === "M" ? offset : 0 ),
9067 day = Math.min( inst.selectedDay, this._getDaysInMonth( year, month ) ) + ( period === "D" ? offset : 0 ),
9068 date = this._restrictMinMax( inst, this._daylightSavingAdjust( new Date( year, month, day ) ) );
9070 inst.selectedDay = date.getDate();
9071 inst.drawMonth = inst.selectedMonth = date.getMonth();
9072 inst.drawYear = inst.selectedYear = date.getFullYear();
9073 if ( period === "M" || period === "Y" ) {
9074 this._notifyChange( inst );
9078 /* Ensure a date is within any min/max bounds. */
9079 _restrictMinMax: function( inst, date ) {
9080 var minDate = this._getMinMaxDate( inst, "min" ),
9081 maxDate = this._getMinMaxDate( inst, "max" ),
9082 newDate = ( minDate && date < minDate ? minDate : date );
9083 return ( maxDate && newDate > maxDate ? maxDate : newDate );
9086 /* Notify change of month/year. */
9087 _notifyChange: function( inst ) {
9088 var onChange = this._get( inst, "onChangeMonthYear" );
9090 onChange.apply( ( inst.input ? inst.input[ 0 ] : null ),
9091 [ inst.selectedYear, inst.selectedMonth + 1, inst ] );
9095 /* Determine the number of months to show. */
9096 _getNumberOfMonths: function( inst ) {
9097 var numMonths = this._get( inst, "numberOfMonths" );
9098 return ( numMonths == null ? [ 1, 1 ] : ( typeof numMonths === "number" ? [ 1, numMonths ] : numMonths ) );
9101 /* Determine the current maximum date - ensure no time components are set. */
9102 _getMinMaxDate: function( inst, minMax ) {
9103 return this._determineDate( inst, this._get( inst, minMax + "Date" ), null );
9106 /* Find the number of days in a given month. */
9107 _getDaysInMonth: function( year, month ) {
9108 return 32 - this._daylightSavingAdjust( new Date( year, month, 32 ) ).getDate();
9111 /* Find the day of the week of the first of a month. */
9112 _getFirstDayOfMonth: function( year, month ) {
9113 return new Date( year, month, 1 ).getDay();
9116 /* Determines if we should allow a "next/prev" month display change. */
9117 _canAdjustMonth: function( inst, offset, curYear, curMonth ) {
9118 var numMonths = this._getNumberOfMonths( inst ),
9119 date = this._daylightSavingAdjust( new Date( curYear,
9120 curMonth + ( offset < 0 ? offset : numMonths[ 0 ] * numMonths[ 1 ] ), 1 ) );
9123 date.setDate( this._getDaysInMonth( date.getFullYear(), date.getMonth() ) );
9125 return this._isInRange( inst, date );
9128 /* Is the given date in the accepted range? */
9129 _isInRange: function( inst, date ) {
9130 var yearSplit, currentYear,
9131 minDate = this._getMinMaxDate( inst, "min" ),
9132 maxDate = this._getMinMaxDate( inst, "max" ),
9135 years = this._get( inst, "yearRange" );
9137 yearSplit = years.split( ":" );
9138 currentYear = new Date().getFullYear();
9139 minYear = parseInt( yearSplit[ 0 ], 10 );
9140 maxYear = parseInt( yearSplit[ 1 ], 10 );
9141 if ( yearSplit[ 0 ].match( /[+\-].*/ ) ) {
9142 minYear += currentYear;
9144 if ( yearSplit[ 1 ].match( /[+\-].*/ ) ) {
9145 maxYear += currentYear;
9149 return ( ( !minDate || date.getTime() >= minDate.getTime() ) &&
9150 ( !maxDate || date.getTime() <= maxDate.getTime() ) &&
9151 ( !minYear || date.getFullYear() >= minYear ) &&
9152 ( !maxYear || date.getFullYear() <= maxYear ) );
9155 /* Provide the configuration settings for formatting/parsing. */
9156 _getFormatConfig: function( inst ) {
9157 var shortYearCutoff = this._get( inst, "shortYearCutoff" );
9158 shortYearCutoff = ( typeof shortYearCutoff !== "string" ? shortYearCutoff :
9159 new Date().getFullYear() % 100 + parseInt( shortYearCutoff, 10 ) );
9160 return { shortYearCutoff: shortYearCutoff,
9161 dayNamesShort: this._get( inst, "dayNamesShort" ), dayNames: this._get( inst, "dayNames" ),
9162 monthNamesShort: this._get( inst, "monthNamesShort" ), monthNames: this._get( inst, "monthNames" ) };
9165 /* Format the given date for display. */
9166 _formatDate: function( inst, day, month, year ) {
9168 inst.currentDay = inst.selectedDay;
9169 inst.currentMonth = inst.selectedMonth;
9170 inst.currentYear = inst.selectedYear;
9172 var date = ( day ? ( typeof day === "object" ? day :
9173 this._daylightSavingAdjust( new Date( year, month, day ) ) ) :
9174 this._daylightSavingAdjust( new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
9175 return this.formatDate( this._get( inst, "dateFormat" ), date, this._getFormatConfig( inst ) );
9180 * Bind hover events for datepicker elements.
9181 * Done via delegate so the binding only occurs once in the lifetime of the parent div.
9182 * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
9184 function datepicker_bindHover( dpDiv ) {
9185 var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
9186 return dpDiv.on( "mouseout", selector, function() {
9187 $( this ).removeClass( "ui-state-hover" );
9188 if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
9189 $( this ).removeClass( "ui-datepicker-prev-hover" );
9191 if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
9192 $( this ).removeClass( "ui-datepicker-next-hover" );
9195 .on( "mouseover", selector, datepicker_handleMouseover );
9198 function datepicker_handleMouseover() {
9199 if ( !$.datepicker._isDisabledDatepicker( datepicker_instActive.inline ? datepicker_instActive.dpDiv.parent()[ 0 ] : datepicker_instActive.input[ 0 ] ) ) {
9200 $( this ).parents( ".ui-datepicker-calendar" ).find( "a" ).removeClass( "ui-state-hover" );
9201 $( this ).addClass( "ui-state-hover" );
9202 if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
9203 $( this ).addClass( "ui-datepicker-prev-hover" );
9205 if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
9206 $( this ).addClass( "ui-datepicker-next-hover" );
9211 /* jQuery extend now ignores nulls! */
9212 function datepicker_extendRemove( target, props ) {
9213 $.extend( target, props );
9214 for ( var name in props ) {
9215 if ( props[ name ] == null ) {
9216 target[ name ] = props[ name ];
9222 /* Invoke the datepicker functionality.
9223 @param options string - a command, optionally followed by additional parameters or
9224 Object - settings for attaching new datepicker functionality
9225 @return jQuery object */
9226 $.fn.datepicker = function( options ) {
9228 /* Verify an empty collection wasn't passed - Fixes #6976 */
9229 if ( !this.length ) {
9233 /* Initialise the date picker. */
9234 if ( !$.datepicker.initialized ) {
9235 $( document ).on( "mousedown", $.datepicker._checkExternalClick );
9236 $.datepicker.initialized = true;
9239 /* Append datepicker main container to body if not exist. */
9240 if ( $( "#" + $.datepicker._mainDivId ).length === 0 ) {
9241 $( "body" ).append( $.datepicker.dpDiv );
9244 var otherArgs = Array.prototype.slice.call( arguments, 1 );
9245 if ( typeof options === "string" && ( options === "isDisabled" || options === "getDate" || options === "widget" ) ) {
9246 return $.datepicker[ "_" + options + "Datepicker" ].
9247 apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
9249 if ( options === "option" && arguments.length === 2 && typeof arguments[ 1 ] === "string" ) {
9250 return $.datepicker[ "_" + options + "Datepicker" ].
9251 apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
9253 return this.each( function() {
9254 typeof options === "string" ?
9255 $.datepicker[ "_" + options + "Datepicker" ].
9256 apply( $.datepicker, [ this ].concat( otherArgs ) ) :
9257 $.datepicker._attachDatepicker( this, options );
9261 $.datepicker = new Datepicker(); // singleton instance
9262 $.datepicker.initialized = false;
9263 $.datepicker.uuid = new Date().getTime();
9264 $.datepicker.version = "1.12.1";
9266 var widgetsDatepicker = $.datepicker;
9271 // This file is deprecated
9272 var ie = $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
9275 * jQuery UI Mouse 1.12.1
9276 * http://jqueryui.com
9278 * Copyright jQuery Foundation and other contributors
9279 * Released under the MIT license.
9280 * http://jquery.org/license
9285 //>>description: Abstracts mouse-based interactions to assist in creating certain widgets.
9286 //>>docs: http://api.jqueryui.com/mouse/
9290 var mouseHandled = false;
9291 $( document ).on( "mouseup", function() {
9292 mouseHandled = false;
9295 var widgetsMouse = $.widget( "ui.mouse", {
9298 cancel: "input, textarea, button, select, option",
9302 _mouseInit: function() {
9306 .on( "mousedown." + this.widgetName, function( event ) {
9307 return that._mouseDown( event );
9309 .on( "click." + this.widgetName, function( event ) {
9310 if ( true === $.data( event.target, that.widgetName + ".preventClickEvent" ) ) {
9311 $.removeData( event.target, that.widgetName + ".preventClickEvent" );
9312 event.stopImmediatePropagation();
9317 this.started = false;
9320 // TODO: make sure destroying one instance of mouse doesn't mess with
9321 // other instances of mouse
9322 _mouseDestroy: function() {
9323 this.element.off( "." + this.widgetName );
9324 if ( this._mouseMoveDelegate ) {
9326 .off( "mousemove." + this.widgetName, this._mouseMoveDelegate )
9327 .off( "mouseup." + this.widgetName, this._mouseUpDelegate );
9331 _mouseDown: function( event ) {
9333 // don't let more than one widget handle mouseStart
9334 if ( mouseHandled ) {
9338 this._mouseMoved = false;
9340 // We may have missed mouseup (out of window)
9341 ( this._mouseStarted && this._mouseUp( event ) );
9343 this._mouseDownEvent = event;
9346 btnIsLeft = ( event.which === 1 ),
9348 // event.target.nodeName works around a bug in IE 8 with
9349 // disabled inputs (#7620)
9350 elIsCancel = ( typeof this.options.cancel === "string" && event.target.nodeName ?
9351 $( event.target ).closest( this.options.cancel ).length : false );
9352 if ( !btnIsLeft || elIsCancel || !this._mouseCapture( event ) ) {
9356 this.mouseDelayMet = !this.options.delay;
9357 if ( !this.mouseDelayMet ) {
9358 this._mouseDelayTimer = setTimeout( function() {
9359 that.mouseDelayMet = true;
9360 }, this.options.delay );
9363 if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) {
9364 this._mouseStarted = ( this._mouseStart( event ) !== false );
9365 if ( !this._mouseStarted ) {
9366 event.preventDefault();
9371 // Click event may never have fired (Gecko & Opera)
9372 if ( true === $.data( event.target, this.widgetName + ".preventClickEvent" ) ) {
9373 $.removeData( event.target, this.widgetName + ".preventClickEvent" );
9376 // These delegates are required to keep context
9377 this._mouseMoveDelegate = function( event ) {
9378 return that._mouseMove( event );
9380 this._mouseUpDelegate = function( event ) {
9381 return that._mouseUp( event );
9385 .on( "mousemove." + this.widgetName, this._mouseMoveDelegate )
9386 .on( "mouseup." + this.widgetName, this._mouseUpDelegate );
9388 event.preventDefault();
9390 mouseHandled = true;
9394 _mouseMove: function( event ) {
9396 // Only check for mouseups outside the document if you've moved inside the document
9397 // at least once. This prevents the firing of mouseup in the case of IE<9, which will
9398 // fire a mousemove event if content is placed under the cursor. See #7778
9400 if ( this._mouseMoved ) {
9402 // IE mouseup check - mouseup happened when mouse was out of window
9403 if ( $.ui.ie && ( !document.documentMode || document.documentMode < 9 ) &&
9405 return this._mouseUp( event );
9407 // Iframe mouseup check - mouseup occurred in another document
9408 } else if ( !event.which ) {
9410 // Support: Safari <=8 - 9
9411 // Safari sets which to 0 if you press any of the following keys
9412 // during a drag (#14461)
9413 if ( event.originalEvent.altKey || event.originalEvent.ctrlKey ||
9414 event.originalEvent.metaKey || event.originalEvent.shiftKey ) {
9415 this.ignoreMissingWhich = true;
9416 } else if ( !this.ignoreMissingWhich ) {
9417 return this._mouseUp( event );
9422 if ( event.which || event.button ) {
9423 this._mouseMoved = true;
9426 if ( this._mouseStarted ) {
9427 this._mouseDrag( event );
9428 return event.preventDefault();
9431 if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) {
9432 this._mouseStarted =
9433 ( this._mouseStart( this._mouseDownEvent, event ) !== false );
9434 ( this._mouseStarted ? this._mouseDrag( event ) : this._mouseUp( event ) );
9437 return !this._mouseStarted;
9440 _mouseUp: function( event ) {
9442 .off( "mousemove." + this.widgetName, this._mouseMoveDelegate )
9443 .off( "mouseup." + this.widgetName, this._mouseUpDelegate );
9445 if ( this._mouseStarted ) {
9446 this._mouseStarted = false;
9448 if ( event.target === this._mouseDownEvent.target ) {
9449 $.data( event.target, this.widgetName + ".preventClickEvent", true );
9452 this._mouseStop( event );
9455 if ( this._mouseDelayTimer ) {
9456 clearTimeout( this._mouseDelayTimer );
9457 delete this._mouseDelayTimer;
9460 this.ignoreMissingWhich = false;
9461 mouseHandled = false;
9462 event.preventDefault();
9465 _mouseDistanceMet: function( event ) {
9467 Math.abs( this._mouseDownEvent.pageX - event.pageX ),
9468 Math.abs( this._mouseDownEvent.pageY - event.pageY )
9469 ) >= this.options.distance
9473 _mouseDelayMet: function( /* event */ ) {
9474 return this.mouseDelayMet;
9477 // These are placeholder methods, to be overriden by extending plugin
9478 _mouseStart: function( /* event */ ) {},
9479 _mouseDrag: function( /* event */ ) {},
9480 _mouseStop: function( /* event */ ) {},
9481 _mouseCapture: function( /* event */ ) { return true; }
9487 // $.ui.plugin is deprecated. Use $.widget() extensions instead.
9488 var plugin = $.ui.plugin = {
9489 add: function( module, option, set ) {
9491 proto = $.ui[ module ].prototype;
9493 proto.plugins[ i ] = proto.plugins[ i ] || [];
9494 proto.plugins[ i ].push( [ option, set[ i ] ] );
9497 call: function( instance, name, args, allowDisconnected ) {
9499 set = instance.plugins[ name ];
9505 if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode ||
9506 instance.element[ 0 ].parentNode.nodeType === 11 ) ) {
9510 for ( i = 0; i < set.length; i++ ) {
9511 if ( instance.options[ set[ i ][ 0 ] ] ) {
9512 set[ i ][ 1 ].apply( instance.element, args );
9520 var safeBlur = $.ui.safeBlur = function( element ) {
9522 // Support: IE9 - 10 only
9523 // If the <body> is blurred, IE will switch windows, see #9420
9524 if ( element && element.nodeName.toLowerCase() !== "body" ) {
9525 $( element ).trigger( "blur" );
9531 * jQuery UI Draggable 1.12.1
9532 * http://jqueryui.com
9534 * Copyright jQuery Foundation and other contributors
9535 * Released under the MIT license.
9536 * http://jquery.org/license
9539 //>>label: Draggable
9540 //>>group: Interactions
9541 //>>description: Enables dragging functionality for any element.
9542 //>>docs: http://api.jqueryui.com/draggable/
9543 //>>demos: http://jqueryui.com/draggable/
9544 //>>css.structure: ../../themes/base/draggable.css
9548 $.widget( "ui.draggable", $.ui.mouse, {
9550 widgetEventPrefix: "drag",
9555 connectToSortable: false,
9564 refreshPositions: false,
9566 revertDuration: 500,
9569 scrollSensitivity: 20,
9582 _create: function() {
9584 if ( this.options.helper === "original" ) {
9585 this._setPositionRelative();
9587 if ( this.options.addClasses ) {
9588 this._addClass( "ui-draggable" );
9590 this._setHandleClassName();
9595 _setOption: function( key, value ) {
9596 this._super( key, value );
9597 if ( key === "handle" ) {
9598 this._removeHandleClassName();
9599 this._setHandleClassName();
9603 _destroy: function() {
9604 if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) {
9605 this.destroyOnClear = true;
9608 this._removeHandleClassName();
9609 this._mouseDestroy();
9612 _mouseCapture: function( event ) {
9613 var o = this.options;
9615 // Among others, prevent a drag on a resizable-handle
9616 if ( this.helper || o.disabled ||
9617 $( event.target ).closest( ".ui-resizable-handle" ).length > 0 ) {
9621 //Quit if we're not on a valid handle
9622 this.handle = this._getHandle( event );
9623 if ( !this.handle ) {
9627 this._blurActiveElement( event );
9629 this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix );
9635 _blockFrames: function( selector ) {
9636 this.iframeBlocks = this.document.find( selector ).map( function() {
9637 var iframe = $( this );
9640 .css( "position", "absolute" )
9641 .appendTo( iframe.parent() )
9642 .outerWidth( iframe.outerWidth() )
9643 .outerHeight( iframe.outerHeight() )
9644 .offset( iframe.offset() )[ 0 ];
9648 _unblockFrames: function() {
9649 if ( this.iframeBlocks ) {
9650 this.iframeBlocks.remove();
9651 delete this.iframeBlocks;
9655 _blurActiveElement: function( event ) {
9656 var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ),
9657 target = $( event.target );
9659 // Don't blur if the event occurred on an element that is within
9660 // the currently focused element
9661 // See #10527, #12472
9662 if ( target.closest( activeElement ).length ) {
9666 // Blur any element that currently has focus, see #4261
9667 $.ui.safeBlur( activeElement );
9670 _mouseStart: function( event ) {
9672 var o = this.options;
9674 //Create and append the visible helper
9675 this.helper = this._createHelper( event );
9677 this._addClass( this.helper, "ui-draggable-dragging" );
9679 //Cache the helper size
9680 this._cacheHelperProportions();
9682 //If ddmanager is used for droppables, set the global draggable
9683 if ( $.ui.ddmanager ) {
9684 $.ui.ddmanager.current = this;
9688 * - Position generation -
9689 * This block generates everything position related - it's the core of draggables.
9692 //Cache the margins of the original element
9693 this._cacheMargins();
9695 //Store the helper's css position
9696 this.cssPosition = this.helper.css( "position" );
9697 this.scrollParent = this.helper.scrollParent( true );
9698 this.offsetParent = this.helper.offsetParent();
9699 this.hasFixedAncestor = this.helper.parents().filter( function() {
9700 return $( this ).css( "position" ) === "fixed";
9703 //The element's absolute position on the page minus margins
9704 this.positionAbs = this.element.offset();
9705 this._refreshOffsets( event );
9707 //Generate the original position
9708 this.originalPosition = this.position = this._generatePosition( event, false );
9709 this.originalPageX = event.pageX;
9710 this.originalPageY = event.pageY;
9712 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
9713 ( o.cursorAt && this._adjustOffsetFromHelper( o.cursorAt ) );
9715 //Set a containment if given in the options
9716 this._setContainment();
9718 //Trigger event + callbacks
9719 if ( this._trigger( "start", event ) === false ) {
9724 //Recache the helper size
9725 this._cacheHelperProportions();
9727 //Prepare the droppable offsets
9728 if ( $.ui.ddmanager && !o.dropBehaviour ) {
9729 $.ui.ddmanager.prepareOffsets( this, event );
9732 // Execute the drag once - this causes the helper not to be visible before getting its
9734 this._mouseDrag( event, true );
9736 // If the ddmanager is used for droppables, inform the manager that dragging has started
9738 if ( $.ui.ddmanager ) {
9739 $.ui.ddmanager.dragStart( this, event );
9745 _refreshOffsets: function( event ) {
9747 top: this.positionAbs.top - this.margins.top,
9748 left: this.positionAbs.left - this.margins.left,
9750 parent: this._getParentOffset(),
9751 relative: this._getRelativeOffset()
9754 this.offset.click = {
9755 left: event.pageX - this.offset.left,
9756 top: event.pageY - this.offset.top
9760 _mouseDrag: function( event, noPropagation ) {
9762 // reset any necessary cached properties (see #5009)
9763 if ( this.hasFixedAncestor ) {
9764 this.offset.parent = this._getParentOffset();
9767 //Compute the helpers position
9768 this.position = this._generatePosition( event, true );
9769 this.positionAbs = this._convertPositionTo( "absolute" );
9771 //Call plugins and callbacks and use the resulting position if something is returned
9772 if ( !noPropagation ) {
9773 var ui = this._uiHash();
9774 if ( this._trigger( "drag", event, ui ) === false ) {
9775 this._mouseUp( new $.Event( "mouseup", event ) );
9778 this.position = ui.position;
9781 this.helper[ 0 ].style.left = this.position.left + "px";
9782 this.helper[ 0 ].style.top = this.position.top + "px";
9784 if ( $.ui.ddmanager ) {
9785 $.ui.ddmanager.drag( this, event );
9791 _mouseStop: function( event ) {
9793 //If we are using droppables, inform the manager about the drop
9796 if ( $.ui.ddmanager && !this.options.dropBehaviour ) {
9797 dropped = $.ui.ddmanager.drop( this, event );
9800 //if a drop comes from outside (a sortable)
9801 if ( this.dropped ) {
9802 dropped = this.dropped;
9803 this.dropped = false;
9806 if ( ( this.options.revert === "invalid" && !dropped ) ||
9807 ( this.options.revert === "valid" && dropped ) ||
9808 this.options.revert === true || ( $.isFunction( this.options.revert ) &&
9809 this.options.revert.call( this.element, dropped ) )
9811 $( this.helper ).animate(
9812 this.originalPosition,
9813 parseInt( this.options.revertDuration, 10 ),
9815 if ( that._trigger( "stop", event ) !== false ) {
9821 if ( this._trigger( "stop", event ) !== false ) {
9829 _mouseUp: function( event ) {
9830 this._unblockFrames();
9832 // If the ddmanager is used for droppables, inform the manager that dragging has stopped
9834 if ( $.ui.ddmanager ) {
9835 $.ui.ddmanager.dragStop( this, event );
9838 // Only need to focus if the event occurred on the draggable itself, see #10527
9839 if ( this.handleElement.is( event.target ) ) {
9841 // The interaction is over; whether or not the click resulted in a drag,
9842 // focus the element
9843 this.element.trigger( "focus" );
9846 return $.ui.mouse.prototype._mouseUp.call( this, event );
9849 cancel: function() {
9851 if ( this.helper.is( ".ui-draggable-dragging" ) ) {
9852 this._mouseUp( new $.Event( "mouseup", { target: this.element[ 0 ] } ) );
9861 _getHandle: function( event ) {
9862 return this.options.handle ?
9863 !!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
9867 _setHandleClassName: function() {
9868 this.handleElement = this.options.handle ?
9869 this.element.find( this.options.handle ) : this.element;
9870 this._addClass( this.handleElement, "ui-draggable-handle" );
9873 _removeHandleClassName: function() {
9874 this._removeClass( this.handleElement, "ui-draggable-handle" );
9877 _createHelper: function( event ) {
9879 var o = this.options,
9880 helperIsFunction = $.isFunction( o.helper ),
9881 helper = helperIsFunction ?
9882 $( o.helper.apply( this.element[ 0 ], [ event ] ) ) :
9883 ( o.helper === "clone" ?
9884 this.element.clone().removeAttr( "id" ) :
9887 if ( !helper.parents( "body" ).length ) {
9888 helper.appendTo( ( o.appendTo === "parent" ?
9889 this.element[ 0 ].parentNode :
9893 // Http://bugs.jqueryui.com/ticket/9446
9894 // a helper function can return the original element
9895 // which wouldn't have been set to relative in _create
9896 if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) {
9897 this._setPositionRelative();
9900 if ( helper[ 0 ] !== this.element[ 0 ] &&
9901 !( /(fixed|absolute)/ ).test( helper.css( "position" ) ) ) {
9902 helper.css( "position", "absolute" );
9909 _setPositionRelative: function() {
9910 if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) {
9911 this.element[ 0 ].style.position = "relative";
9915 _adjustOffsetFromHelper: function( obj ) {
9916 if ( typeof obj === "string" ) {
9917 obj = obj.split( " " );
9919 if ( $.isArray( obj ) ) {
9920 obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 };
9922 if ( "left" in obj ) {
9923 this.offset.click.left = obj.left + this.margins.left;
9925 if ( "right" in obj ) {
9926 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
9928 if ( "top" in obj ) {
9929 this.offset.click.top = obj.top + this.margins.top;
9931 if ( "bottom" in obj ) {
9932 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
9936 _isRootNode: function( element ) {
9937 return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ];
9940 _getParentOffset: function() {
9942 //Get the offsetParent and cache its position
9943 var po = this.offsetParent.offset(),
9944 document = this.document[ 0 ];
9946 // This is a special case where we need to modify a offset calculated on start, since the
9947 // following happened:
9948 // 1. The position of the helper is absolute, so it's position is calculated based on the
9949 // next positioned parent
9950 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't
9951 // the document, which means that the scroll is included in the initial calculation of the
9952 // offset of the parent, and never recalculated upon drag
9953 if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== document &&
9954 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) {
9955 po.left += this.scrollParent.scrollLeft();
9956 po.top += this.scrollParent.scrollTop();
9959 if ( this._isRootNode( this.offsetParent[ 0 ] ) ) {
9960 po = { top: 0, left: 0 };
9964 top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ),
9965 left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 )
9970 _getRelativeOffset: function() {
9971 if ( this.cssPosition !== "relative" ) {
9972 return { top: 0, left: 0 };
9975 var p = this.element.position(),
9976 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
9979 top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) +
9980 ( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ),
9981 left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) +
9982 ( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 )
9987 _cacheMargins: function() {
9989 left: ( parseInt( this.element.css( "marginLeft" ), 10 ) || 0 ),
9990 top: ( parseInt( this.element.css( "marginTop" ), 10 ) || 0 ),
9991 right: ( parseInt( this.element.css( "marginRight" ), 10 ) || 0 ),
9992 bottom: ( parseInt( this.element.css( "marginBottom" ), 10 ) || 0 )
9996 _cacheHelperProportions: function() {
9997 this.helperProportions = {
9998 width: this.helper.outerWidth(),
9999 height: this.helper.outerHeight()
10003 _setContainment: function() {
10005 var isUserScrollable, c, ce,
10007 document = this.document[ 0 ];
10009 this.relativeContainer = null;
10011 if ( !o.containment ) {
10012 this.containment = null;
10016 if ( o.containment === "window" ) {
10017 this.containment = [
10018 $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
10019 $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
10020 $( window ).scrollLeft() + $( window ).width() -
10021 this.helperProportions.width - this.margins.left,
10022 $( window ).scrollTop() +
10023 ( $( window ).height() || document.body.parentNode.scrollHeight ) -
10024 this.helperProportions.height - this.margins.top
10029 if ( o.containment === "document" ) {
10030 this.containment = [
10033 $( document ).width() - this.helperProportions.width - this.margins.left,
10034 ( $( document ).height() || document.body.parentNode.scrollHeight ) -
10035 this.helperProportions.height - this.margins.top
10040 if ( o.containment.constructor === Array ) {
10041 this.containment = o.containment;
10045 if ( o.containment === "parent" ) {
10046 o.containment = this.helper[ 0 ].parentNode;
10049 c = $( o.containment );
10056 isUserScrollable = /(scroll|auto)/.test( c.css( "overflow" ) );
10058 this.containment = [
10059 ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) +
10060 ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
10061 ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) +
10062 ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ),
10063 ( isUserScrollable ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
10064 ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) -
10065 ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) -
10066 this.helperProportions.width -
10067 this.margins.left -
10068 this.margins.right,
10069 ( isUserScrollable ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
10070 ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) -
10071 ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) -
10072 this.helperProportions.height -
10074 this.margins.bottom
10076 this.relativeContainer = c;
10079 _convertPositionTo: function( d, pos ) {
10082 pos = this.position;
10085 var mod = d === "absolute" ? 1 : -1,
10086 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
10091 // The absolute mouse position
10094 // Only for relative positioned nodes: Relative offset from element to offset parent
10095 this.offset.relative.top * mod +
10097 // The offsetParent's offset without borders (offset + border)
10098 this.offset.parent.top * mod -
10099 ( ( this.cssPosition === "fixed" ?
10100 -this.offset.scroll.top :
10101 ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod )
10105 // The absolute mouse position
10108 // Only for relative positioned nodes: Relative offset from element to offset parent
10109 this.offset.relative.left * mod +
10111 // The offsetParent's offset without borders (offset + border)
10112 this.offset.parent.left * mod -
10113 ( ( this.cssPosition === "fixed" ?
10114 -this.offset.scroll.left :
10115 ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod )
10121 _generatePosition: function( event, constrainPosition ) {
10123 var containment, co, top, left,
10125 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ),
10126 pageX = event.pageX,
10127 pageY = event.pageY;
10129 // Cache the scroll
10130 if ( !scrollIsRootNode || !this.offset.scroll ) {
10131 this.offset.scroll = {
10132 top: this.scrollParent.scrollTop(),
10133 left: this.scrollParent.scrollLeft()
10138 * - Position constraining -
10139 * Constrain the position to a mix of grid, containment.
10142 // If we are not dragging yet, we won't check for options
10143 if ( constrainPosition ) {
10144 if ( this.containment ) {
10145 if ( this.relativeContainer ) {
10146 co = this.relativeContainer.offset();
10148 this.containment[ 0 ] + co.left,
10149 this.containment[ 1 ] + co.top,
10150 this.containment[ 2 ] + co.left,
10151 this.containment[ 3 ] + co.top
10154 containment = this.containment;
10157 if ( event.pageX - this.offset.click.left < containment[ 0 ] ) {
10158 pageX = containment[ 0 ] + this.offset.click.left;
10160 if ( event.pageY - this.offset.click.top < containment[ 1 ] ) {
10161 pageY = containment[ 1 ] + this.offset.click.top;
10163 if ( event.pageX - this.offset.click.left > containment[ 2 ] ) {
10164 pageX = containment[ 2 ] + this.offset.click.left;
10166 if ( event.pageY - this.offset.click.top > containment[ 3 ] ) {
10167 pageY = containment[ 3 ] + this.offset.click.top;
10173 //Check for grid elements set to 0 to prevent divide by 0 error causing invalid
10174 // argument errors in IE (see ticket #6950)
10175 top = o.grid[ 1 ] ? this.originalPageY + Math.round( ( pageY -
10176 this.originalPageY ) / o.grid[ 1 ] ) * o.grid[ 1 ] : this.originalPageY;
10177 pageY = containment ? ( ( top - this.offset.click.top >= containment[ 1 ] ||
10178 top - this.offset.click.top > containment[ 3 ] ) ?
10180 ( ( top - this.offset.click.top >= containment[ 1 ] ) ?
10181 top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) : top;
10183 left = o.grid[ 0 ] ? this.originalPageX +
10184 Math.round( ( pageX - this.originalPageX ) / o.grid[ 0 ] ) * o.grid[ 0 ] :
10185 this.originalPageX;
10186 pageX = containment ? ( ( left - this.offset.click.left >= containment[ 0 ] ||
10187 left - this.offset.click.left > containment[ 2 ] ) ?
10189 ( ( left - this.offset.click.left >= containment[ 0 ] ) ?
10190 left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) : left;
10193 if ( o.axis === "y" ) {
10194 pageX = this.originalPageX;
10197 if ( o.axis === "x" ) {
10198 pageY = this.originalPageY;
10205 // The absolute mouse position
10208 // Click offset (relative to the element)
10209 this.offset.click.top -
10211 // Only for relative positioned nodes: Relative offset from element to offset parent
10212 this.offset.relative.top -
10214 // The offsetParent's offset without borders (offset + border)
10215 this.offset.parent.top +
10216 ( this.cssPosition === "fixed" ?
10217 -this.offset.scroll.top :
10218 ( scrollIsRootNode ? 0 : this.offset.scroll.top ) )
10222 // The absolute mouse position
10225 // Click offset (relative to the element)
10226 this.offset.click.left -
10228 // Only for relative positioned nodes: Relative offset from element to offset parent
10229 this.offset.relative.left -
10231 // The offsetParent's offset without borders (offset + border)
10232 this.offset.parent.left +
10233 ( this.cssPosition === "fixed" ?
10234 -this.offset.scroll.left :
10235 ( scrollIsRootNode ? 0 : this.offset.scroll.left ) )
10241 _clear: function() {
10242 this._removeClass( this.helper, "ui-draggable-dragging" );
10243 if ( this.helper[ 0 ] !== this.element[ 0 ] && !this.cancelHelperRemoval ) {
10244 this.helper.remove();
10246 this.helper = null;
10247 this.cancelHelperRemoval = false;
10248 if ( this.destroyOnClear ) {
10253 // From now on bulk stuff - mainly helpers
10255 _trigger: function( type, event, ui ) {
10256 ui = ui || this._uiHash();
10257 $.ui.plugin.call( this, type, [ event, ui, this ], true );
10259 // Absolute position and offset (see #6884 ) have to be recalculated after plugins
10260 if ( /^(drag|start|stop)/.test( type ) ) {
10261 this.positionAbs = this._convertPositionTo( "absolute" );
10262 ui.offset = this.positionAbs;
10264 return $.Widget.prototype._trigger.call( this, type, event, ui );
10269 _uiHash: function() {
10271 helper: this.helper,
10272 position: this.position,
10273 originalPosition: this.originalPosition,
10274 offset: this.positionAbs
10280 $.ui.plugin.add( "draggable", "connectToSortable", {
10281 start: function( event, ui, draggable ) {
10282 var uiSortable = $.extend( {}, ui, {
10283 item: draggable.element
10286 draggable.sortables = [];
10287 $( draggable.options.connectToSortable ).each( function() {
10288 var sortable = $( this ).sortable( "instance" );
10290 if ( sortable && !sortable.options.disabled ) {
10291 draggable.sortables.push( sortable );
10293 // RefreshPositions is called at drag start to refresh the containerCache
10294 // which is used in drag. This ensures it's initialized and synchronized
10295 // with any changes that might have happened on the page since initialization.
10296 sortable.refreshPositions();
10297 sortable._trigger( "activate", event, uiSortable );
10301 stop: function( event, ui, draggable ) {
10302 var uiSortable = $.extend( {}, ui, {
10303 item: draggable.element
10306 draggable.cancelHelperRemoval = false;
10308 $.each( draggable.sortables, function() {
10309 var sortable = this;
10311 if ( sortable.isOver ) {
10312 sortable.isOver = 0;
10314 // Allow this sortable to handle removing the helper
10315 draggable.cancelHelperRemoval = true;
10316 sortable.cancelHelperRemoval = false;
10318 // Use _storedCSS To restore properties in the sortable,
10319 // as this also handles revert (#9675) since the draggable
10320 // may have modified them in unexpected ways (#8809)
10321 sortable._storedCSS = {
10322 position: sortable.placeholder.css( "position" ),
10323 top: sortable.placeholder.css( "top" ),
10324 left: sortable.placeholder.css( "left" )
10327 sortable._mouseStop( event );
10329 // Once drag has ended, the sortable should return to using
10330 // its original helper, not the shared helper from draggable
10331 sortable.options.helper = sortable.options._helper;
10334 // Prevent this Sortable from removing the helper.
10335 // However, don't set the draggable to remove the helper
10336 // either as another connected Sortable may yet handle the removal.
10337 sortable.cancelHelperRemoval = true;
10339 sortable._trigger( "deactivate", event, uiSortable );
10343 drag: function( event, ui, draggable ) {
10344 $.each( draggable.sortables, function() {
10345 var innermostIntersecting = false,
10348 // Copy over variables that sortable's _intersectsWith uses
10349 sortable.positionAbs = draggable.positionAbs;
10350 sortable.helperProportions = draggable.helperProportions;
10351 sortable.offset.click = draggable.offset.click;
10353 if ( sortable._intersectsWith( sortable.containerCache ) ) {
10354 innermostIntersecting = true;
10356 $.each( draggable.sortables, function() {
10358 // Copy over variables that sortable's _intersectsWith uses
10359 this.positionAbs = draggable.positionAbs;
10360 this.helperProportions = draggable.helperProportions;
10361 this.offset.click = draggable.offset.click;
10363 if ( this !== sortable &&
10364 this._intersectsWith( this.containerCache ) &&
10365 $.contains( sortable.element[ 0 ], this.element[ 0 ] ) ) {
10366 innermostIntersecting = false;
10369 return innermostIntersecting;
10373 if ( innermostIntersecting ) {
10375 // If it intersects, we use a little isOver variable and set it once,
10376 // so that the move-in stuff gets fired only once.
10377 if ( !sortable.isOver ) {
10378 sortable.isOver = 1;
10380 // Store draggable's parent in case we need to reappend to it later.
10381 draggable._parent = ui.helper.parent();
10383 sortable.currentItem = ui.helper
10384 .appendTo( sortable.element )
10385 .data( "ui-sortable-item", true );
10387 // Store helper option to later restore it
10388 sortable.options._helper = sortable.options.helper;
10390 sortable.options.helper = function() {
10391 return ui.helper[ 0 ];
10394 // Fire the start events of the sortable with our passed browser event,
10395 // and our own helper (so it doesn't create a new one)
10396 event.target = sortable.currentItem[ 0 ];
10397 sortable._mouseCapture( event, true );
10398 sortable._mouseStart( event, true, true );
10400 // Because the browser event is way off the new appended portlet,
10401 // modify necessary variables to reflect the changes
10402 sortable.offset.click.top = draggable.offset.click.top;
10403 sortable.offset.click.left = draggable.offset.click.left;
10404 sortable.offset.parent.left -= draggable.offset.parent.left -
10405 sortable.offset.parent.left;
10406 sortable.offset.parent.top -= draggable.offset.parent.top -
10407 sortable.offset.parent.top;
10409 draggable._trigger( "toSortable", event );
10411 // Inform draggable that the helper is in a valid drop zone,
10412 // used solely in the revert option to handle "valid/invalid".
10413 draggable.dropped = sortable.element;
10415 // Need to refreshPositions of all sortables in the case that
10416 // adding to one sortable changes the location of the other sortables (#9675)
10417 $.each( draggable.sortables, function() {
10418 this.refreshPositions();
10421 // Hack so receive/update callbacks work (mostly)
10422 draggable.currentItem = draggable.element;
10423 sortable.fromOutside = draggable;
10426 if ( sortable.currentItem ) {
10427 sortable._mouseDrag( event );
10429 // Copy the sortable's position because the draggable's can potentially reflect
10430 // a relative position, while sortable is always absolute, which the dragged
10431 // element has now become. (#8809)
10432 ui.position = sortable.position;
10436 // If it doesn't intersect with the sortable, and it intersected before,
10437 // we fake the drag stop of the sortable, but make sure it doesn't remove
10438 // the helper by using cancelHelperRemoval.
10439 if ( sortable.isOver ) {
10441 sortable.isOver = 0;
10442 sortable.cancelHelperRemoval = true;
10444 // Calling sortable's mouseStop would trigger a revert,
10445 // so revert must be temporarily false until after mouseStop is called.
10446 sortable.options._revert = sortable.options.revert;
10447 sortable.options.revert = false;
10449 sortable._trigger( "out", event, sortable._uiHash( sortable ) );
10450 sortable._mouseStop( event, true );
10452 // Restore sortable behaviors that were modfied
10453 // when the draggable entered the sortable area (#9481)
10454 sortable.options.revert = sortable.options._revert;
10455 sortable.options.helper = sortable.options._helper;
10457 if ( sortable.placeholder ) {
10458 sortable.placeholder.remove();
10461 // Restore and recalculate the draggable's offset considering the sortable
10462 // may have modified them in unexpected ways. (#8809, #10669)
10463 ui.helper.appendTo( draggable._parent );
10464 draggable._refreshOffsets( event );
10465 ui.position = draggable._generatePosition( event, true );
10467 draggable._trigger( "fromSortable", event );
10469 // Inform draggable that the helper is no longer in a valid drop zone
10470 draggable.dropped = false;
10472 // Need to refreshPositions of all sortables just in case removing
10473 // from one sortable changes the location of other sortables (#9675)
10474 $.each( draggable.sortables, function() {
10475 this.refreshPositions();
10483 $.ui.plugin.add( "draggable", "cursor", {
10484 start: function( event, ui, instance ) {
10485 var t = $( "body" ),
10486 o = instance.options;
10488 if ( t.css( "cursor" ) ) {
10489 o._cursor = t.css( "cursor" );
10491 t.css( "cursor", o.cursor );
10493 stop: function( event, ui, instance ) {
10494 var o = instance.options;
10496 $( "body" ).css( "cursor", o._cursor );
10501 $.ui.plugin.add( "draggable", "opacity", {
10502 start: function( event, ui, instance ) {
10503 var t = $( ui.helper ),
10504 o = instance.options;
10505 if ( t.css( "opacity" ) ) {
10506 o._opacity = t.css( "opacity" );
10508 t.css( "opacity", o.opacity );
10510 stop: function( event, ui, instance ) {
10511 var o = instance.options;
10512 if ( o._opacity ) {
10513 $( ui.helper ).css( "opacity", o._opacity );
10518 $.ui.plugin.add( "draggable", "scroll", {
10519 start: function( event, ui, i ) {
10520 if ( !i.scrollParentNotHidden ) {
10521 i.scrollParentNotHidden = i.helper.scrollParent( false );
10524 if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] &&
10525 i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) {
10526 i.overflowOffset = i.scrollParentNotHidden.offset();
10529 drag: function( event, ui, i ) {
10533 scrollParent = i.scrollParentNotHidden[ 0 ],
10534 document = i.document[ 0 ];
10536 if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) {
10537 if ( !o.axis || o.axis !== "x" ) {
10538 if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY <
10539 o.scrollSensitivity ) {
10540 scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed;
10541 } else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) {
10542 scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed;
10546 if ( !o.axis || o.axis !== "y" ) {
10547 if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX <
10548 o.scrollSensitivity ) {
10549 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed;
10550 } else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) {
10551 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed;
10557 if ( !o.axis || o.axis !== "x" ) {
10558 if ( event.pageY - $( document ).scrollTop() < o.scrollSensitivity ) {
10559 scrolled = $( document ).scrollTop( $( document ).scrollTop() - o.scrollSpeed );
10560 } else if ( $( window ).height() - ( event.pageY - $( document ).scrollTop() ) <
10561 o.scrollSensitivity ) {
10562 scrolled = $( document ).scrollTop( $( document ).scrollTop() + o.scrollSpeed );
10566 if ( !o.axis || o.axis !== "y" ) {
10567 if ( event.pageX - $( document ).scrollLeft() < o.scrollSensitivity ) {
10568 scrolled = $( document ).scrollLeft(
10569 $( document ).scrollLeft() - o.scrollSpeed
10571 } else if ( $( window ).width() - ( event.pageX - $( document ).scrollLeft() ) <
10572 o.scrollSensitivity ) {
10573 scrolled = $( document ).scrollLeft(
10574 $( document ).scrollLeft() + o.scrollSpeed
10581 if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) {
10582 $.ui.ddmanager.prepareOffsets( i, event );
10588 $.ui.plugin.add( "draggable", "snap", {
10589 start: function( event, ui, i ) {
10593 i.snapElements = [];
10595 $( o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap )
10596 .each( function() {
10597 var $t = $( this ),
10599 if ( this !== i.element[ 0 ] ) {
10600 i.snapElements.push( {
10602 width: $t.outerWidth(), height: $t.outerHeight(),
10603 top: $o.top, left: $o.left
10609 drag: function( event, ui, inst ) {
10611 var ts, bs, ls, rs, l, r, t, b, i, first,
10613 d = o.snapTolerance,
10614 x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
10615 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
10617 for ( i = inst.snapElements.length - 1; i >= 0; i-- ) {
10619 l = inst.snapElements[ i ].left - inst.margins.left;
10620 r = l + inst.snapElements[ i ].width;
10621 t = inst.snapElements[ i ].top - inst.margins.top;
10622 b = t + inst.snapElements[ i ].height;
10624 if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d ||
10625 !$.contains( inst.snapElements[ i ].item.ownerDocument,
10626 inst.snapElements[ i ].item ) ) {
10627 if ( inst.snapElements[ i ].snapping ) {
10628 ( inst.options.snap.release &&
10629 inst.options.snap.release.call(
10632 $.extend( inst._uiHash(), { snapItem: inst.snapElements[ i ].item } )
10635 inst.snapElements[ i ].snapping = false;
10639 if ( o.snapMode !== "inner" ) {
10640 ts = Math.abs( t - y2 ) <= d;
10641 bs = Math.abs( b - y1 ) <= d;
10642 ls = Math.abs( l - x2 ) <= d;
10643 rs = Math.abs( r - x1 ) <= d;
10645 ui.position.top = inst._convertPositionTo( "relative", {
10646 top: t - inst.helperProportions.height,
10651 ui.position.top = inst._convertPositionTo( "relative", {
10657 ui.position.left = inst._convertPositionTo( "relative", {
10659 left: l - inst.helperProportions.width
10663 ui.position.left = inst._convertPositionTo( "relative", {
10670 first = ( ts || bs || ls || rs );
10672 if ( o.snapMode !== "outer" ) {
10673 ts = Math.abs( t - y1 ) <= d;
10674 bs = Math.abs( b - y2 ) <= d;
10675 ls = Math.abs( l - x1 ) <= d;
10676 rs = Math.abs( r - x2 ) <= d;
10678 ui.position.top = inst._convertPositionTo( "relative", {
10684 ui.position.top = inst._convertPositionTo( "relative", {
10685 top: b - inst.helperProportions.height,
10690 ui.position.left = inst._convertPositionTo( "relative", {
10696 ui.position.left = inst._convertPositionTo( "relative", {
10698 left: r - inst.helperProportions.width
10703 if ( !inst.snapElements[ i ].snapping && ( ts || bs || ls || rs || first ) ) {
10704 ( inst.options.snap.snap &&
10705 inst.options.snap.snap.call(
10708 $.extend( inst._uiHash(), {
10709 snapItem: inst.snapElements[ i ].item
10712 inst.snapElements[ i ].snapping = ( ts || bs || ls || rs || first );
10719 $.ui.plugin.add( "draggable", "stack", {
10720 start: function( event, ui, instance ) {
10722 o = instance.options,
10723 group = $.makeArray( $( o.stack ) ).sort( function( a, b ) {
10724 return ( parseInt( $( a ).css( "zIndex" ), 10 ) || 0 ) -
10725 ( parseInt( $( b ).css( "zIndex" ), 10 ) || 0 );
10728 if ( !group.length ) { return; }
10730 min = parseInt( $( group[ 0 ] ).css( "zIndex" ), 10 ) || 0;
10731 $( group ).each( function( i ) {
10732 $( this ).css( "zIndex", min + i );
10734 this.css( "zIndex", ( min + group.length ) );
10738 $.ui.plugin.add( "draggable", "zIndex", {
10739 start: function( event, ui, instance ) {
10740 var t = $( ui.helper ),
10741 o = instance.options;
10743 if ( t.css( "zIndex" ) ) {
10744 o._zIndex = t.css( "zIndex" );
10746 t.css( "zIndex", o.zIndex );
10748 stop: function( event, ui, instance ) {
10749 var o = instance.options;
10752 $( ui.helper ).css( "zIndex", o._zIndex );
10757 var widgetsDraggable = $.ui.draggable;
10761 * jQuery UI Resizable 1.12.1
10762 * http://jqueryui.com
10764 * Copyright jQuery Foundation and other contributors
10765 * Released under the MIT license.
10766 * http://jquery.org/license
10769 //>>label: Resizable
10770 //>>group: Interactions
10771 //>>description: Enables resize functionality for any element.
10772 //>>docs: http://api.jqueryui.com/resizable/
10773 //>>demos: http://jqueryui.com/resizable/
10774 //>>css.structure: ../../themes/base/core.css
10775 //>>css.structure: ../../themes/base/resizable.css
10776 //>>css.theme: ../../themes/base/theme.css
10780 $.widget( "ui.resizable", $.ui.mouse, {
10782 widgetEventPrefix: "resize",
10786 animateDuration: "slow",
10787 animateEasing: "swing",
10788 aspectRatio: false,
10791 "ui-resizable-se": "ui-icon ui-icon-gripsmall-diagonal-se"
10793 containment: false,
10812 _num: function( value ) {
10813 return parseFloat( value ) || 0;
10816 _isNumber: function( value ) {
10817 return !isNaN( parseFloat( value ) );
10820 _hasScroll: function( el, a ) {
10822 if ( $( el ).css( "overflow" ) === "hidden" ) {
10826 var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
10829 if ( el[ scroll ] > 0 ) {
10833 // TODO: determine which cases actually cause this to happen
10834 // if the element doesn't have the scroll set, see if it's possible to
10837 has = ( el[ scroll ] > 0 );
10842 _create: function() {
10847 this._addClass( "ui-resizable" );
10850 _aspectRatio: !!( o.aspectRatio ),
10851 aspectRatio: o.aspectRatio,
10852 originalElement: this.element,
10853 _proportionallyResizeElements: [],
10854 _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
10857 // Wrap the element if it cannot hold child nodes
10858 if ( this.element[ 0 ].nodeName.match( /^(canvas|textarea|input|select|button|img)$/i ) ) {
10861 $( "<div class='ui-wrapper' style='overflow: hidden;'></div>" ).css( {
10862 position: this.element.css( "position" ),
10863 width: this.element.outerWidth(),
10864 height: this.element.outerHeight(),
10865 top: this.element.css( "top" ),
10866 left: this.element.css( "left" )
10870 this.element = this.element.parent().data(
10871 "ui-resizable", this.element.resizable( "instance" )
10874 this.elementIsWrapper = true;
10877 marginTop: this.originalElement.css( "marginTop" ),
10878 marginRight: this.originalElement.css( "marginRight" ),
10879 marginBottom: this.originalElement.css( "marginBottom" ),
10880 marginLeft: this.originalElement.css( "marginLeft" )
10883 this.element.css( margins );
10884 this.originalElement.css( "margin", 0 );
10887 // Prevent Safari textarea resize
10888 this.originalResizeStyle = this.originalElement.css( "resize" );
10889 this.originalElement.css( "resize", "none" );
10891 this._proportionallyResizeElements.push( this.originalElement.css( {
10892 position: "static",
10898 // avoid IE jump (hard set the margin)
10899 this.originalElement.css( margins );
10901 this._proportionallyResize();
10904 this._setupHandles();
10906 if ( o.autoHide ) {
10908 .on( "mouseenter", function() {
10909 if ( o.disabled ) {
10912 that._removeClass( "ui-resizable-autohide" );
10913 that._handles.show();
10915 .on( "mouseleave", function() {
10916 if ( o.disabled ) {
10919 if ( !that.resizing ) {
10920 that._addClass( "ui-resizable-autohide" );
10921 that._handles.hide();
10929 _destroy: function() {
10931 this._mouseDestroy();
10934 _destroy = function( exp ) {
10936 .removeData( "resizable" )
10937 .removeData( "ui-resizable" )
10938 .off( ".resizable" )
10939 .find( ".ui-resizable-handle" )
10943 // TODO: Unwrap at same DOM position
10944 if ( this.elementIsWrapper ) {
10945 _destroy( this.element );
10946 wrapper = this.element;
10947 this.originalElement.css( {
10948 position: wrapper.css( "position" ),
10949 width: wrapper.outerWidth(),
10950 height: wrapper.outerHeight(),
10951 top: wrapper.css( "top" ),
10952 left: wrapper.css( "left" )
10953 } ).insertAfter( wrapper );
10957 this.originalElement.css( "resize", this.originalResizeStyle );
10958 _destroy( this.originalElement );
10963 _setOption: function( key, value ) {
10964 this._super( key, value );
10968 this._removeHandles();
10969 this._setupHandles();
10976 _setupHandles: function() {
10977 var o = this.options, handle, i, n, hname, axis, that = this;
10978 this.handles = o.handles ||
10979 ( !$( ".ui-resizable-handle", this.element ).length ?
10981 n: ".ui-resizable-n",
10982 e: ".ui-resizable-e",
10983 s: ".ui-resizable-s",
10984 w: ".ui-resizable-w",
10985 se: ".ui-resizable-se",
10986 sw: ".ui-resizable-sw",
10987 ne: ".ui-resizable-ne",
10988 nw: ".ui-resizable-nw"
10991 this._handles = $();
10992 if ( this.handles.constructor === String ) {
10994 if ( this.handles === "all" ) {
10995 this.handles = "n,e,s,w,se,sw,ne,nw";
10998 n = this.handles.split( "," );
11001 for ( i = 0; i < n.length; i++ ) {
11003 handle = $.trim( n[ i ] );
11004 hname = "ui-resizable-" + handle;
11005 axis = $( "<div>" );
11006 this._addClass( axis, "ui-resizable-handle " + hname );
11008 axis.css( { zIndex: o.zIndex } );
11010 this.handles[ handle ] = ".ui-resizable-" + handle;
11011 this.element.append( axis );
11016 this._renderAxis = function( target ) {
11018 var i, axis, padPos, padWrapper;
11020 target = target || this.element;
11022 for ( i in this.handles ) {
11024 if ( this.handles[ i ].constructor === String ) {
11025 this.handles[ i ] = this.element.children( this.handles[ i ] ).first().show();
11026 } else if ( this.handles[ i ].jquery || this.handles[ i ].nodeType ) {
11027 this.handles[ i ] = $( this.handles[ i ] );
11028 this._on( this.handles[ i ], { "mousedown": that._mouseDown } );
11031 if ( this.elementIsWrapper &&
11032 this.originalElement[ 0 ]
11034 .match( /^(textarea|input|select|button)$/i ) ) {
11035 axis = $( this.handles[ i ], this.element );
11037 padWrapper = /sw|ne|nw|se|n|s/.test( i ) ?
11038 axis.outerHeight() :
11041 padPos = [ "padding",
11042 /ne|nw|n/.test( i ) ? "Top" :
11043 /se|sw|s/.test( i ) ? "Bottom" :
11044 /^e$/.test( i ) ? "Right" : "Left" ].join( "" );
11046 target.css( padPos, padWrapper );
11048 this._proportionallyResize();
11051 this._handles = this._handles.add( this.handles[ i ] );
11055 // TODO: make renderAxis a prototype function
11056 this._renderAxis( this.element );
11058 this._handles = this._handles.add( this.element.find( ".ui-resizable-handle" ) );
11059 this._handles.disableSelection();
11061 this._handles.on( "mouseover", function() {
11062 if ( !that.resizing ) {
11063 if ( this.className ) {
11064 axis = this.className.match( /ui-resizable-(se|sw|ne|nw|n|e|s|w)/i );
11066 that.axis = axis && axis[ 1 ] ? axis[ 1 ] : "se";
11070 if ( o.autoHide ) {
11071 this._handles.hide();
11072 this._addClass( "ui-resizable-autohide" );
11076 _removeHandles: function() {
11077 this._handles.remove();
11080 _mouseCapture: function( event ) {
11084 for ( i in this.handles ) {
11085 handle = $( this.handles[ i ] )[ 0 ];
11086 if ( handle === event.target || $.contains( handle, event.target ) ) {
11091 return !this.options.disabled && capture;
11094 _mouseStart: function( event ) {
11096 var curleft, curtop, cursor,
11100 this.resizing = true;
11102 this._renderProxy();
11104 curleft = this._num( this.helper.css( "left" ) );
11105 curtop = this._num( this.helper.css( "top" ) );
11107 if ( o.containment ) {
11108 curleft += $( o.containment ).scrollLeft() || 0;
11109 curtop += $( o.containment ).scrollTop() || 0;
11112 this.offset = this.helper.offset();
11113 this.position = { left: curleft, top: curtop };
11115 this.size = this._helper ? {
11116 width: this.helper.width(),
11117 height: this.helper.height()
11120 height: el.height()
11123 this.originalSize = this._helper ? {
11124 width: el.outerWidth(),
11125 height: el.outerHeight()
11128 height: el.height()
11132 width: el.outerWidth() - el.width(),
11133 height: el.outerHeight() - el.height()
11136 this.originalPosition = { left: curleft, top: curtop };
11137 this.originalMousePosition = { left: event.pageX, top: event.pageY };
11139 this.aspectRatio = ( typeof o.aspectRatio === "number" ) ?
11141 ( ( this.originalSize.width / this.originalSize.height ) || 1 );
11143 cursor = $( ".ui-resizable-" + this.axis ).css( "cursor" );
11144 $( "body" ).css( "cursor", cursor === "auto" ? this.axis + "-resize" : cursor );
11146 this._addClass( "ui-resizable-resizing" );
11147 this._propagate( "start", event );
11151 _mouseDrag: function( event ) {
11154 smp = this.originalMousePosition,
11156 dx = ( event.pageX - smp.left ) || 0,
11157 dy = ( event.pageY - smp.top ) || 0,
11158 trigger = this._change[ a ];
11160 this._updatePrevProperties();
11166 data = trigger.apply( this, [ event, dx, dy ] );
11168 this._updateVirtualBoundaries( event.shiftKey );
11169 if ( this._aspectRatio || event.shiftKey ) {
11170 data = this._updateRatio( data, event );
11173 data = this._respectSize( data, event );
11175 this._updateCache( data );
11177 this._propagate( "resize", event );
11179 props = this._applyChanges();
11181 if ( !this._helper && this._proportionallyResizeElements.length ) {
11182 this._proportionallyResize();
11185 if ( !$.isEmptyObject( props ) ) {
11186 this._updatePrevProperties();
11187 this._trigger( "resize", event, this.ui() );
11188 this._applyChanges();
11194 _mouseStop: function( event ) {
11196 this.resizing = false;
11197 var pr, ista, soffseth, soffsetw, s, left, top,
11198 o = this.options, that = this;
11200 if ( this._helper ) {
11202 pr = this._proportionallyResizeElements;
11203 ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName );
11204 soffseth = ista && this._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height;
11205 soffsetw = ista ? 0 : that.sizeDiff.width;
11208 width: ( that.helper.width() - soffsetw ),
11209 height: ( that.helper.height() - soffseth )
11211 left = ( parseFloat( that.element.css( "left" ) ) +
11212 ( that.position.left - that.originalPosition.left ) ) || null;
11213 top = ( parseFloat( that.element.css( "top" ) ) +
11214 ( that.position.top - that.originalPosition.top ) ) || null;
11216 if ( !o.animate ) {
11217 this.element.css( $.extend( s, { top: top, left: left } ) );
11220 that.helper.height( that.size.height );
11221 that.helper.width( that.size.width );
11223 if ( this._helper && !o.animate ) {
11224 this._proportionallyResize();
11228 $( "body" ).css( "cursor", "auto" );
11230 this._removeClass( "ui-resizable-resizing" );
11232 this._propagate( "stop", event );
11234 if ( this._helper ) {
11235 this.helper.remove();
11242 _updatePrevProperties: function() {
11243 this.prevPosition = {
11244 top: this.position.top,
11245 left: this.position.left
11248 width: this.size.width,
11249 height: this.size.height
11253 _applyChanges: function() {
11256 if ( this.position.top !== this.prevPosition.top ) {
11257 props.top = this.position.top + "px";
11259 if ( this.position.left !== this.prevPosition.left ) {
11260 props.left = this.position.left + "px";
11262 if ( this.size.width !== this.prevSize.width ) {
11263 props.width = this.size.width + "px";
11265 if ( this.size.height !== this.prevSize.height ) {
11266 props.height = this.size.height + "px";
11269 this.helper.css( props );
11274 _updateVirtualBoundaries: function( forceAspectRatio ) {
11275 var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
11279 minWidth: this._isNumber( o.minWidth ) ? o.minWidth : 0,
11280 maxWidth: this._isNumber( o.maxWidth ) ? o.maxWidth : Infinity,
11281 minHeight: this._isNumber( o.minHeight ) ? o.minHeight : 0,
11282 maxHeight: this._isNumber( o.maxHeight ) ? o.maxHeight : Infinity
11285 if ( this._aspectRatio || forceAspectRatio ) {
11286 pMinWidth = b.minHeight * this.aspectRatio;
11287 pMinHeight = b.minWidth / this.aspectRatio;
11288 pMaxWidth = b.maxHeight * this.aspectRatio;
11289 pMaxHeight = b.maxWidth / this.aspectRatio;
11291 if ( pMinWidth > b.minWidth ) {
11292 b.minWidth = pMinWidth;
11294 if ( pMinHeight > b.minHeight ) {
11295 b.minHeight = pMinHeight;
11297 if ( pMaxWidth < b.maxWidth ) {
11298 b.maxWidth = pMaxWidth;
11300 if ( pMaxHeight < b.maxHeight ) {
11301 b.maxHeight = pMaxHeight;
11304 this._vBoundaries = b;
11307 _updateCache: function( data ) {
11308 this.offset = this.helper.offset();
11309 if ( this._isNumber( data.left ) ) {
11310 this.position.left = data.left;
11312 if ( this._isNumber( data.top ) ) {
11313 this.position.top = data.top;
11315 if ( this._isNumber( data.height ) ) {
11316 this.size.height = data.height;
11318 if ( this._isNumber( data.width ) ) {
11319 this.size.width = data.width;
11323 _updateRatio: function( data ) {
11325 var cpos = this.position,
11329 if ( this._isNumber( data.height ) ) {
11330 data.width = ( data.height * this.aspectRatio );
11331 } else if ( this._isNumber( data.width ) ) {
11332 data.height = ( data.width / this.aspectRatio );
11335 if ( a === "sw" ) {
11336 data.left = cpos.left + ( csize.width - data.width );
11339 if ( a === "nw" ) {
11340 data.top = cpos.top + ( csize.height - data.height );
11341 data.left = cpos.left + ( csize.width - data.width );
11347 _respectSize: function( data ) {
11349 var o = this._vBoundaries,
11351 ismaxw = this._isNumber( data.width ) && o.maxWidth && ( o.maxWidth < data.width ),
11352 ismaxh = this._isNumber( data.height ) && o.maxHeight && ( o.maxHeight < data.height ),
11353 isminw = this._isNumber( data.width ) && o.minWidth && ( o.minWidth > data.width ),
11354 isminh = this._isNumber( data.height ) && o.minHeight && ( o.minHeight > data.height ),
11355 dw = this.originalPosition.left + this.originalSize.width,
11356 dh = this.originalPosition.top + this.originalSize.height,
11357 cw = /sw|nw|w/.test( a ), ch = /nw|ne|n/.test( a );
11359 data.width = o.minWidth;
11362 data.height = o.minHeight;
11365 data.width = o.maxWidth;
11368 data.height = o.maxHeight;
11371 if ( isminw && cw ) {
11372 data.left = dw - o.minWidth;
11374 if ( ismaxw && cw ) {
11375 data.left = dw - o.maxWidth;
11377 if ( isminh && ch ) {
11378 data.top = dh - o.minHeight;
11380 if ( ismaxh && ch ) {
11381 data.top = dh - o.maxHeight;
11384 // Fixing jump error on top/left - bug #2330
11385 if ( !data.width && !data.height && !data.left && data.top ) {
11387 } else if ( !data.width && !data.height && !data.top && data.left ) {
11394 _getPaddingPlusBorderDimensions: function( element ) {
11398 element.css( "borderTopWidth" ),
11399 element.css( "borderRightWidth" ),
11400 element.css( "borderBottomWidth" ),
11401 element.css( "borderLeftWidth" )
11404 element.css( "paddingTop" ),
11405 element.css( "paddingRight" ),
11406 element.css( "paddingBottom" ),
11407 element.css( "paddingLeft" )
11410 for ( ; i < 4; i++ ) {
11411 widths[ i ] = ( parseFloat( borders[ i ] ) || 0 );
11412 widths[ i ] += ( parseFloat( paddings[ i ] ) || 0 );
11416 height: widths[ 0 ] + widths[ 2 ],
11417 width: widths[ 1 ] + widths[ 3 ]
11421 _proportionallyResize: function() {
11423 if ( !this._proportionallyResizeElements.length ) {
11429 element = this.helper || this.element;
11431 for ( ; i < this._proportionallyResizeElements.length; i++ ) {
11433 prel = this._proportionallyResizeElements[ i ];
11435 // TODO: Seems like a bug to cache this.outerDimensions
11436 // considering that we are in a loop.
11437 if ( !this.outerDimensions ) {
11438 this.outerDimensions = this._getPaddingPlusBorderDimensions( prel );
11442 height: ( element.height() - this.outerDimensions.height ) || 0,
11443 width: ( element.width() - this.outerDimensions.width ) || 0
11450 _renderProxy: function() {
11452 var el = this.element, o = this.options;
11453 this.elementOffset = el.offset();
11455 if ( this._helper ) {
11457 this.helper = this.helper || $( "<div style='overflow:hidden;'></div>" );
11459 this._addClass( this.helper, this._helper );
11461 width: this.element.outerWidth(),
11462 height: this.element.outerHeight(),
11463 position: "absolute",
11464 left: this.elementOffset.left + "px",
11465 top: this.elementOffset.top + "px",
11466 zIndex: ++o.zIndex //TODO: Don't modify option
11470 .appendTo( "body" )
11471 .disableSelection();
11474 this.helper = this.element;
11480 e: function( event, dx ) {
11481 return { width: this.originalSize.width + dx };
11483 w: function( event, dx ) {
11484 var cs = this.originalSize, sp = this.originalPosition;
11485 return { left: sp.left + dx, width: cs.width - dx };
11487 n: function( event, dx, dy ) {
11488 var cs = this.originalSize, sp = this.originalPosition;
11489 return { top: sp.top + dy, height: cs.height - dy };
11491 s: function( event, dx, dy ) {
11492 return { height: this.originalSize.height + dy };
11494 se: function( event, dx, dy ) {
11495 return $.extend( this._change.s.apply( this, arguments ),
11496 this._change.e.apply( this, [ event, dx, dy ] ) );
11498 sw: function( event, dx, dy ) {
11499 return $.extend( this._change.s.apply( this, arguments ),
11500 this._change.w.apply( this, [ event, dx, dy ] ) );
11502 ne: function( event, dx, dy ) {
11503 return $.extend( this._change.n.apply( this, arguments ),
11504 this._change.e.apply( this, [ event, dx, dy ] ) );
11506 nw: function( event, dx, dy ) {
11507 return $.extend( this._change.n.apply( this, arguments ),
11508 this._change.w.apply( this, [ event, dx, dy ] ) );
11512 _propagate: function( n, event ) {
11513 $.ui.plugin.call( this, n, [ event, this.ui() ] );
11514 ( n !== "resize" && this._trigger( n, event, this.ui() ) );
11521 originalElement: this.originalElement,
11522 element: this.element,
11523 helper: this.helper,
11524 position: this.position,
11526 originalSize: this.originalSize,
11527 originalPosition: this.originalPosition
11534 * Resizable Extensions
11537 $.ui.plugin.add( "resizable", "animate", {
11539 stop: function( event ) {
11540 var that = $( this ).resizable( "instance" ),
11542 pr = that._proportionallyResizeElements,
11543 ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName ),
11544 soffseth = ista && that._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height,
11545 soffsetw = ista ? 0 : that.sizeDiff.width,
11547 width: ( that.size.width - soffsetw ),
11548 height: ( that.size.height - soffseth )
11550 left = ( parseFloat( that.element.css( "left" ) ) +
11551 ( that.position.left - that.originalPosition.left ) ) || null,
11552 top = ( parseFloat( that.element.css( "top" ) ) +
11553 ( that.position.top - that.originalPosition.top ) ) || null;
11555 that.element.animate(
11556 $.extend( style, top && left ? { top: top, left: left } : {} ), {
11557 duration: o.animateDuration,
11558 easing: o.animateEasing,
11562 width: parseFloat( that.element.css( "width" ) ),
11563 height: parseFloat( that.element.css( "height" ) ),
11564 top: parseFloat( that.element.css( "top" ) ),
11565 left: parseFloat( that.element.css( "left" ) )
11568 if ( pr && pr.length ) {
11569 $( pr[ 0 ] ).css( { width: data.width, height: data.height } );
11572 // Propagating resize, and updating values for each animation step
11573 that._updateCache( data );
11574 that._propagate( "resize", event );
11583 $.ui.plugin.add( "resizable", "containment", {
11585 start: function() {
11586 var element, p, co, ch, cw, width, height,
11587 that = $( this ).resizable( "instance" ),
11590 oc = o.containment,
11591 ce = ( oc instanceof $ ) ?
11593 ( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc;
11599 that.containerElement = $( ce );
11601 if ( /document/.test( oc ) || oc === document ) {
11602 that.containerOffset = {
11606 that.containerPosition = {
11611 that.parentData = {
11612 element: $( document ),
11615 width: $( document ).width(),
11616 height: $( document ).height() || document.body.parentNode.scrollHeight
11621 $( [ "Top", "Right", "Left", "Bottom" ] ).each( function( i, name ) {
11622 p[ i ] = that._num( element.css( "padding" + name ) );
11625 that.containerOffset = element.offset();
11626 that.containerPosition = element.position();
11627 that.containerSize = {
11628 height: ( element.innerHeight() - p[ 3 ] ),
11629 width: ( element.innerWidth() - p[ 1 ] )
11632 co = that.containerOffset;
11633 ch = that.containerSize.height;
11634 cw = that.containerSize.width;
11635 width = ( that._hasScroll ( ce, "left" ) ? ce.scrollWidth : cw );
11636 height = ( that._hasScroll ( ce ) ? ce.scrollHeight : ch ) ;
11638 that.parentData = {
11648 resize: function( event ) {
11649 var woset, hoset, isParent, isOffsetRelative,
11650 that = $( this ).resizable( "instance" ),
11652 co = that.containerOffset,
11653 cp = that.position,
11654 pRatio = that._aspectRatio || event.shiftKey,
11659 ce = that.containerElement,
11660 continueResize = true;
11662 if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) {
11666 if ( cp.left < ( that._helper ? co.left : 0 ) ) {
11667 that.size.width = that.size.width +
11669 ( that.position.left - co.left ) :
11670 ( that.position.left - cop.left ) );
11673 that.size.height = that.size.width / that.aspectRatio;
11674 continueResize = false;
11676 that.position.left = o.helper ? co.left : 0;
11679 if ( cp.top < ( that._helper ? co.top : 0 ) ) {
11680 that.size.height = that.size.height +
11682 ( that.position.top - co.top ) :
11683 that.position.top );
11686 that.size.width = that.size.height * that.aspectRatio;
11687 continueResize = false;
11689 that.position.top = that._helper ? co.top : 0;
11692 isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 );
11693 isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) );
11695 if ( isParent && isOffsetRelative ) {
11696 that.offset.left = that.parentData.left + that.position.left;
11697 that.offset.top = that.parentData.top + that.position.top;
11699 that.offset.left = that.element.offset().left;
11700 that.offset.top = that.element.offset().top;
11703 woset = Math.abs( that.sizeDiff.width +
11705 that.offset.left - cop.left :
11706 ( that.offset.left - co.left ) ) );
11708 hoset = Math.abs( that.sizeDiff.height +
11710 that.offset.top - cop.top :
11711 ( that.offset.top - co.top ) ) );
11713 if ( woset + that.size.width >= that.parentData.width ) {
11714 that.size.width = that.parentData.width - woset;
11716 that.size.height = that.size.width / that.aspectRatio;
11717 continueResize = false;
11721 if ( hoset + that.size.height >= that.parentData.height ) {
11722 that.size.height = that.parentData.height - hoset;
11724 that.size.width = that.size.height * that.aspectRatio;
11725 continueResize = false;
11729 if ( !continueResize ) {
11730 that.position.left = that.prevPosition.left;
11731 that.position.top = that.prevPosition.top;
11732 that.size.width = that.prevSize.width;
11733 that.size.height = that.prevSize.height;
11738 var that = $( this ).resizable( "instance" ),
11740 co = that.containerOffset,
11741 cop = that.containerPosition,
11742 ce = that.containerElement,
11743 helper = $( that.helper ),
11744 ho = helper.offset(),
11745 w = helper.outerWidth() - that.sizeDiff.width,
11746 h = helper.outerHeight() - that.sizeDiff.height;
11748 if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) {
11750 left: ho.left - cop.left - co.left,
11756 if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) {
11758 left: ho.left - cop.left - co.left,
11766 $.ui.plugin.add( "resizable", "alsoResize", {
11768 start: function() {
11769 var that = $( this ).resizable( "instance" ),
11772 $( o.alsoResize ).each( function() {
11773 var el = $( this );
11774 el.data( "ui-resizable-alsoresize", {
11775 width: parseFloat( el.width() ), height: parseFloat( el.height() ),
11776 left: parseFloat( el.css( "left" ) ), top: parseFloat( el.css( "top" ) )
11781 resize: function( event, ui ) {
11782 var that = $( this ).resizable( "instance" ),
11784 os = that.originalSize,
11785 op = that.originalPosition,
11787 height: ( that.size.height - os.height ) || 0,
11788 width: ( that.size.width - os.width ) || 0,
11789 top: ( that.position.top - op.top ) || 0,
11790 left: ( that.position.left - op.left ) || 0
11793 $( o.alsoResize ).each( function() {
11794 var el = $( this ), start = $( this ).data( "ui-resizable-alsoresize" ), style = {},
11795 css = el.parents( ui.originalElement[ 0 ] ).length ?
11796 [ "width", "height" ] :
11797 [ "width", "height", "top", "left" ];
11799 $.each( css, function( i, prop ) {
11800 var sum = ( start[ prop ] || 0 ) + ( delta[ prop ] || 0 );
11801 if ( sum && sum >= 0 ) {
11802 style[ prop ] = sum || null;
11811 $( this ).removeData( "ui-resizable-alsoresize" );
11815 $.ui.plugin.add( "resizable", "ghost", {
11817 start: function() {
11819 var that = $( this ).resizable( "instance" ), cs = that.size;
11821 that.ghost = that.originalElement.clone();
11825 position: "relative",
11833 that._addClass( that.ghost, "ui-resizable-ghost" );
11836 // TODO: remove after 1.12
11837 if ( $.uiBackCompat !== false && typeof that.options.ghost === "string" ) {
11840 that.ghost.addClass( this.options.ghost );
11843 that.ghost.appendTo( that.helper );
11847 resize: function() {
11848 var that = $( this ).resizable( "instance" );
11849 if ( that.ghost ) {
11851 position: "relative",
11852 height: that.size.height,
11853 width: that.size.width
11859 var that = $( this ).resizable( "instance" );
11860 if ( that.ghost && that.helper ) {
11861 that.helper.get( 0 ).removeChild( that.ghost.get( 0 ) );
11867 $.ui.plugin.add( "resizable", "grid", {
11869 resize: function() {
11870 var outerDimensions,
11871 that = $( this ).resizable( "instance" ),
11874 os = that.originalSize,
11875 op = that.originalPosition,
11877 grid = typeof o.grid === "number" ? [ o.grid, o.grid ] : o.grid,
11878 gridX = ( grid[ 0 ] || 1 ),
11879 gridY = ( grid[ 1 ] || 1 ),
11880 ox = Math.round( ( cs.width - os.width ) / gridX ) * gridX,
11881 oy = Math.round( ( cs.height - os.height ) / gridY ) * gridY,
11882 newWidth = os.width + ox,
11883 newHeight = os.height + oy,
11884 isMaxWidth = o.maxWidth && ( o.maxWidth < newWidth ),
11885 isMaxHeight = o.maxHeight && ( o.maxHeight < newHeight ),
11886 isMinWidth = o.minWidth && ( o.minWidth > newWidth ),
11887 isMinHeight = o.minHeight && ( o.minHeight > newHeight );
11891 if ( isMinWidth ) {
11894 if ( isMinHeight ) {
11895 newHeight += gridY;
11897 if ( isMaxWidth ) {
11900 if ( isMaxHeight ) {
11901 newHeight -= gridY;
11904 if ( /^(se|s|e)$/.test( a ) ) {
11905 that.size.width = newWidth;
11906 that.size.height = newHeight;
11907 } else if ( /^(ne)$/.test( a ) ) {
11908 that.size.width = newWidth;
11909 that.size.height = newHeight;
11910 that.position.top = op.top - oy;
11911 } else if ( /^(sw)$/.test( a ) ) {
11912 that.size.width = newWidth;
11913 that.size.height = newHeight;
11914 that.position.left = op.left - ox;
11916 if ( newHeight - gridY <= 0 || newWidth - gridX <= 0 ) {
11917 outerDimensions = that._getPaddingPlusBorderDimensions( this );
11920 if ( newHeight - gridY > 0 ) {
11921 that.size.height = newHeight;
11922 that.position.top = op.top - oy;
11924 newHeight = gridY - outerDimensions.height;
11925 that.size.height = newHeight;
11926 that.position.top = op.top + os.height - newHeight;
11928 if ( newWidth - gridX > 0 ) {
11929 that.size.width = newWidth;
11930 that.position.left = op.left - ox;
11932 newWidth = gridX - outerDimensions.width;
11933 that.size.width = newWidth;
11934 that.position.left = op.left + os.width - newWidth;
11941 var widgetsResizable = $.ui.resizable;
11945 * jQuery UI Dialog 1.12.1
11946 * http://jqueryui.com
11948 * Copyright jQuery Foundation and other contributors
11949 * Released under the MIT license.
11950 * http://jquery.org/license
11955 //>>description: Displays customizable dialog windows.
11956 //>>docs: http://api.jqueryui.com/dialog/
11957 //>>demos: http://jqueryui.com/dialog/
11958 //>>css.structure: ../../themes/base/core.css
11959 //>>css.structure: ../../themes/base/dialog.css
11960 //>>css.theme: ../../themes/base/theme.css
11964 $.widget( "ui.dialog", {
11971 "ui-dialog": "ui-corner-all",
11972 "ui-dialog-titlebar": "ui-corner-all"
11974 closeOnEscape: true,
11975 closeText: "Close",
11990 // Ensure the titlebar is always visible
11991 using: function( pos ) {
11992 var topOffset = $( this ).css( pos ).offset().top;
11993 if ( topOffset < 0 ) {
11994 $( this ).css( "top", pos.top - topOffset );
12016 sizeRelatedOptions: {
12026 resizableRelatedOptions: {
12033 _create: function() {
12034 this.originalCss = {
12035 display: this.element[ 0 ].style.display,
12036 width: this.element[ 0 ].style.width,
12037 minHeight: this.element[ 0 ].style.minHeight,
12038 maxHeight: this.element[ 0 ].style.maxHeight,
12039 height: this.element[ 0 ].style.height
12041 this.originalPosition = {
12042 parent: this.element.parent(),
12043 index: this.element.parent().children().index( this.element )
12045 this.originalTitle = this.element.attr( "title" );
12046 if ( this.options.title == null && this.originalTitle != null ) {
12047 this.options.title = this.originalTitle;
12050 // Dialogs can't be disabled
12051 if ( this.options.disabled ) {
12052 this.options.disabled = false;
12055 this._createWrapper();
12059 .removeAttr( "title" )
12060 .appendTo( this.uiDialog );
12062 this._addClass( "ui-dialog-content", "ui-widget-content" );
12064 this._createTitlebar();
12065 this._createButtonPane();
12067 if ( this.options.draggable && $.fn.draggable ) {
12068 this._makeDraggable();
12070 if ( this.options.resizable && $.fn.resizable ) {
12071 this._makeResizable();
12074 this._isOpen = false;
12076 this._trackFocus();
12079 _init: function() {
12080 if ( this.options.autoOpen ) {
12085 _appendTo: function() {
12086 var element = this.options.appendTo;
12087 if ( element && ( element.jquery || element.nodeType ) ) {
12088 return $( element );
12090 return this.document.find( element || "body" ).eq( 0 );
12093 _destroy: function() {
12095 originalPosition = this.originalPosition;
12097 this._untrackInstance();
12098 this._destroyOverlay();
12102 .css( this.originalCss )
12104 // Without detaching first, the following becomes really slow
12107 this.uiDialog.remove();
12109 if ( this.originalTitle ) {
12110 this.element.attr( "title", this.originalTitle );
12113 next = originalPosition.parent.children().eq( originalPosition.index );
12115 // Don't try to place the dialog next to itself (#8613)
12116 if ( next.length && next[ 0 ] !== this.element[ 0 ] ) {
12117 next.before( this.element );
12119 originalPosition.parent.append( this.element );
12123 widget: function() {
12124 return this.uiDialog;
12130 close: function( event ) {
12133 if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) {
12137 this._isOpen = false;
12138 this._focusedElement = null;
12139 this._destroyOverlay();
12140 this._untrackInstance();
12142 if ( !this.opener.filter( ":focusable" ).trigger( "focus" ).length ) {
12144 // Hiding a focused element doesn't trigger blur in WebKit
12145 // so in case we have nothing to focus on, explicitly blur the active element
12146 // https://bugs.webkit.org/show_bug.cgi?id=47182
12147 $.ui.safeBlur( $.ui.safeActiveElement( this.document[ 0 ] ) );
12150 this._hide( this.uiDialog, this.options.hide, function() {
12151 that._trigger( "close", event );
12155 isOpen: function() {
12156 return this._isOpen;
12159 moveToTop: function() {
12163 _moveToTop: function( event, silent ) {
12165 zIndices = this.uiDialog.siblings( ".ui-front:visible" ).map( function() {
12166 return +$( this ).css( "z-index" );
12168 zIndexMax = Math.max.apply( null, zIndices );
12170 if ( zIndexMax >= +this.uiDialog.css( "z-index" ) ) {
12171 this.uiDialog.css( "z-index", zIndexMax + 1 );
12175 if ( moved && !silent ) {
12176 this._trigger( "focus", event );
12183 if ( this._isOpen ) {
12184 if ( this._moveToTop() ) {
12185 this._focusTabbable();
12190 this._isOpen = true;
12191 this.opener = $( $.ui.safeActiveElement( this.document[ 0 ] ) );
12195 this._createOverlay();
12196 this._moveToTop( null, true );
12198 // Ensure the overlay is moved to the top with the dialog, but only when
12199 // opening. The overlay shouldn't move after the dialog is open so that
12200 // modeless dialogs opened after the modal dialog stack properly.
12201 if ( this.overlay ) {
12202 this.overlay.css( "z-index", this.uiDialog.css( "z-index" ) - 1 );
12205 this._show( this.uiDialog, this.options.show, function() {
12206 that._focusTabbable();
12207 that._trigger( "focus" );
12210 // Track the dialog immediately upon openening in case a focus event
12211 // somehow occurs outside of the dialog before an element inside the
12212 // dialog is focused (#10152)
12213 this._makeFocusTarget();
12215 this._trigger( "open" );
12218 _focusTabbable: function() {
12220 // Set focus to the first match:
12221 // 1. An element that was focused previously
12222 // 2. First element inside the dialog matching [autofocus]
12223 // 3. Tabbable element inside the content element
12224 // 4. Tabbable element inside the buttonpane
12225 // 5. The close button
12226 // 6. The dialog itself
12227 var hasFocus = this._focusedElement;
12229 hasFocus = this.element.find( "[autofocus]" );
12231 if ( !hasFocus.length ) {
12232 hasFocus = this.element.find( ":tabbable" );
12234 if ( !hasFocus.length ) {
12235 hasFocus = this.uiDialogButtonPane.find( ":tabbable" );
12237 if ( !hasFocus.length ) {
12238 hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" );
12240 if ( !hasFocus.length ) {
12241 hasFocus = this.uiDialog;
12243 hasFocus.eq( 0 ).trigger( "focus" );
12246 _keepFocus: function( event ) {
12247 function checkFocus() {
12248 var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ),
12249 isActive = this.uiDialog[ 0 ] === activeElement ||
12250 $.contains( this.uiDialog[ 0 ], activeElement );
12252 this._focusTabbable();
12255 event.preventDefault();
12256 checkFocus.call( this );
12259 // IE <= 8 doesn't prevent moving focus even with event.preventDefault()
12260 // so we check again later
12261 this._delay( checkFocus );
12264 _createWrapper: function() {
12265 this.uiDialog = $( "<div>" )
12269 // Setting tabIndex makes the div focusable
12273 .appendTo( this._appendTo() );
12275 this._addClass( this.uiDialog, "ui-dialog", "ui-widget ui-widget-content ui-front" );
12276 this._on( this.uiDialog, {
12277 keydown: function( event ) {
12278 if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
12279 event.keyCode === $.ui.keyCode.ESCAPE ) {
12280 event.preventDefault();
12281 this.close( event );
12285 // Prevent tabbing out of dialogs
12286 if ( event.keyCode !== $.ui.keyCode.TAB || event.isDefaultPrevented() ) {
12289 var tabbables = this.uiDialog.find( ":tabbable" ),
12290 first = tabbables.filter( ":first" ),
12291 last = tabbables.filter( ":last" );
12293 if ( ( event.target === last[ 0 ] || event.target === this.uiDialog[ 0 ] ) &&
12294 !event.shiftKey ) {
12295 this._delay( function() {
12296 first.trigger( "focus" );
12298 event.preventDefault();
12299 } else if ( ( event.target === first[ 0 ] ||
12300 event.target === this.uiDialog[ 0 ] ) && event.shiftKey ) {
12301 this._delay( function() {
12302 last.trigger( "focus" );
12304 event.preventDefault();
12307 mousedown: function( event ) {
12308 if ( this._moveToTop( event ) ) {
12309 this._focusTabbable();
12314 // We assume that any existing aria-describedby attribute means
12315 // that the dialog content is marked up properly
12316 // otherwise we brute force the content as the description
12317 if ( !this.element.find( "[aria-describedby]" ).length ) {
12318 this.uiDialog.attr( {
12319 "aria-describedby": this.element.uniqueId().attr( "id" )
12324 _createTitlebar: function() {
12327 this.uiDialogTitlebar = $( "<div>" );
12328 this._addClass( this.uiDialogTitlebar,
12329 "ui-dialog-titlebar", "ui-widget-header ui-helper-clearfix" );
12330 this._on( this.uiDialogTitlebar, {
12331 mousedown: function( event ) {
12333 // Don't prevent click on close button (#8838)
12334 // Focusing a dialog that is partially scrolled out of view
12335 // causes the browser to scroll it into view, preventing the click event
12336 if ( !$( event.target ).closest( ".ui-dialog-titlebar-close" ) ) {
12338 // Dialog isn't getting focus when dragging (#8063)
12339 this.uiDialog.trigger( "focus" );
12345 // Use type="button" to prevent enter keypresses in textboxes from closing the
12346 // dialog in IE (#9312)
12347 this.uiDialogTitlebarClose = $( "<button type='button'></button>" )
12349 label: $( "<a>" ).text( this.options.closeText ).html(),
12350 icon: "ui-icon-closethick",
12353 .appendTo( this.uiDialogTitlebar );
12355 this._addClass( this.uiDialogTitlebarClose, "ui-dialog-titlebar-close" );
12356 this._on( this.uiDialogTitlebarClose, {
12357 click: function( event ) {
12358 event.preventDefault();
12359 this.close( event );
12363 uiDialogTitle = $( "<span>" ).uniqueId().prependTo( this.uiDialogTitlebar );
12364 this._addClass( uiDialogTitle, "ui-dialog-title" );
12365 this._title( uiDialogTitle );
12367 this.uiDialogTitlebar.prependTo( this.uiDialog );
12369 this.uiDialog.attr( {
12370 "aria-labelledby": uiDialogTitle.attr( "id" )
12374 _title: function( title ) {
12375 if ( this.options.title ) {
12376 title.text( this.options.title );
12378 title.html( " " );
12382 _createButtonPane: function() {
12383 this.uiDialogButtonPane = $( "<div>" );
12384 this._addClass( this.uiDialogButtonPane, "ui-dialog-buttonpane",
12385 "ui-widget-content ui-helper-clearfix" );
12387 this.uiButtonSet = $( "<div>" )
12388 .appendTo( this.uiDialogButtonPane );
12389 this._addClass( this.uiButtonSet, "ui-dialog-buttonset" );
12391 this._createButtons();
12394 _createButtons: function() {
12396 buttons = this.options.buttons;
12398 // If we already have a button pane, remove it
12399 this.uiDialogButtonPane.remove();
12400 this.uiButtonSet.empty();
12402 if ( $.isEmptyObject( buttons ) || ( $.isArray( buttons ) && !buttons.length ) ) {
12403 this._removeClass( this.uiDialog, "ui-dialog-buttons" );
12407 $.each( buttons, function( name, props ) {
12408 var click, buttonOptions;
12409 props = $.isFunction( props ) ?
12410 { click: props, text: name } :
12413 // Default to a non-submitting button
12414 props = $.extend( { type: "button" }, props );
12416 // Change the context for the click callback to be the main element
12417 click = props.click;
12420 iconPosition: props.iconPosition,
12421 showLabel: props.showLabel,
12423 // Deprecated options
12424 icons: props.icons,
12428 delete props.click;
12430 delete props.iconPosition;
12431 delete props.showLabel;
12433 // Deprecated options
12434 delete props.icons;
12435 if ( typeof props.text === "boolean" ) {
12439 $( "<button></button>", props )
12440 .button( buttonOptions )
12441 .appendTo( that.uiButtonSet )
12442 .on( "click", function() {
12443 click.apply( that.element[ 0 ], arguments );
12446 this._addClass( this.uiDialog, "ui-dialog-buttons" );
12447 this.uiDialogButtonPane.appendTo( this.uiDialog );
12450 _makeDraggable: function() {
12452 options = this.options;
12454 function filteredUi( ui ) {
12456 position: ui.position,
12461 this.uiDialog.draggable( {
12462 cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
12463 handle: ".ui-dialog-titlebar",
12464 containment: "document",
12465 start: function( event, ui ) {
12466 that._addClass( $( this ), "ui-dialog-dragging" );
12467 that._blockFrames();
12468 that._trigger( "dragStart", event, filteredUi( ui ) );
12470 drag: function( event, ui ) {
12471 that._trigger( "drag", event, filteredUi( ui ) );
12473 stop: function( event, ui ) {
12474 var left = ui.offset.left - that.document.scrollLeft(),
12475 top = ui.offset.top - that.document.scrollTop();
12477 options.position = {
12479 at: "left" + ( left >= 0 ? "+" : "" ) + left + " " +
12480 "top" + ( top >= 0 ? "+" : "" ) + top,
12483 that._removeClass( $( this ), "ui-dialog-dragging" );
12484 that._unblockFrames();
12485 that._trigger( "dragStop", event, filteredUi( ui ) );
12490 _makeResizable: function() {
12492 options = this.options,
12493 handles = options.resizable,
12495 // .ui-resizable has position: relative defined in the stylesheet
12496 // but dialogs have to use absolute or fixed positioning
12497 position = this.uiDialog.css( "position" ),
12498 resizeHandles = typeof handles === "string" ?
12500 "n,e,s,w,se,sw,ne,nw";
12502 function filteredUi( ui ) {
12504 originalPosition: ui.originalPosition,
12505 originalSize: ui.originalSize,
12506 position: ui.position,
12511 this.uiDialog.resizable( {
12512 cancel: ".ui-dialog-content",
12513 containment: "document",
12514 alsoResize: this.element,
12515 maxWidth: options.maxWidth,
12516 maxHeight: options.maxHeight,
12517 minWidth: options.minWidth,
12518 minHeight: this._minHeight(),
12519 handles: resizeHandles,
12520 start: function( event, ui ) {
12521 that._addClass( $( this ), "ui-dialog-resizing" );
12522 that._blockFrames();
12523 that._trigger( "resizeStart", event, filteredUi( ui ) );
12525 resize: function( event, ui ) {
12526 that._trigger( "resize", event, filteredUi( ui ) );
12528 stop: function( event, ui ) {
12529 var offset = that.uiDialog.offset(),
12530 left = offset.left - that.document.scrollLeft(),
12531 top = offset.top - that.document.scrollTop();
12533 options.height = that.uiDialog.height();
12534 options.width = that.uiDialog.width();
12535 options.position = {
12537 at: "left" + ( left >= 0 ? "+" : "" ) + left + " " +
12538 "top" + ( top >= 0 ? "+" : "" ) + top,
12541 that._removeClass( $( this ), "ui-dialog-resizing" );
12542 that._unblockFrames();
12543 that._trigger( "resizeStop", event, filteredUi( ui ) );
12546 .css( "position", position );
12549 _trackFocus: function() {
12550 this._on( this.widget(), {
12551 focusin: function( event ) {
12552 this._makeFocusTarget();
12553 this._focusedElement = $( event.target );
12558 _makeFocusTarget: function() {
12559 this._untrackInstance();
12560 this._trackingInstances().unshift( this );
12563 _untrackInstance: function() {
12564 var instances = this._trackingInstances(),
12565 exists = $.inArray( this, instances );
12566 if ( exists !== -1 ) {
12567 instances.splice( exists, 1 );
12571 _trackingInstances: function() {
12572 var instances = this.document.data( "ui-dialog-instances" );
12573 if ( !instances ) {
12575 this.document.data( "ui-dialog-instances", instances );
12580 _minHeight: function() {
12581 var options = this.options;
12583 return options.height === "auto" ?
12584 options.minHeight :
12585 Math.min( options.minHeight, options.height );
12588 _position: function() {
12590 // Need to show the dialog to get the actual offset in the position plugin
12591 var isVisible = this.uiDialog.is( ":visible" );
12592 if ( !isVisible ) {
12593 this.uiDialog.show();
12595 this.uiDialog.position( this.options.position );
12596 if ( !isVisible ) {
12597 this.uiDialog.hide();
12601 _setOptions: function( options ) {
12604 resizableOptions = {};
12606 $.each( options, function( key, value ) {
12607 that._setOption( key, value );
12609 if ( key in that.sizeRelatedOptions ) {
12612 if ( key in that.resizableRelatedOptions ) {
12613 resizableOptions[ key ] = value;
12621 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
12622 this.uiDialog.resizable( "option", resizableOptions );
12626 _setOption: function( key, value ) {
12627 var isDraggable, isResizable,
12628 uiDialog = this.uiDialog;
12630 if ( key === "disabled" ) {
12634 this._super( key, value );
12636 if ( key === "appendTo" ) {
12637 this.uiDialog.appendTo( this._appendTo() );
12640 if ( key === "buttons" ) {
12641 this._createButtons();
12644 if ( key === "closeText" ) {
12645 this.uiDialogTitlebarClose.button( {
12647 // Ensure that we always pass a string
12648 label: $( "<a>" ).text( "" + this.options.closeText ).html()
12652 if ( key === "draggable" ) {
12653 isDraggable = uiDialog.is( ":data(ui-draggable)" );
12654 if ( isDraggable && !value ) {
12655 uiDialog.draggable( "destroy" );
12658 if ( !isDraggable && value ) {
12659 this._makeDraggable();
12663 if ( key === "position" ) {
12667 if ( key === "resizable" ) {
12669 // currently resizable, becoming non-resizable
12670 isResizable = uiDialog.is( ":data(ui-resizable)" );
12671 if ( isResizable && !value ) {
12672 uiDialog.resizable( "destroy" );
12675 // Currently resizable, changing handles
12676 if ( isResizable && typeof value === "string" ) {
12677 uiDialog.resizable( "option", "handles", value );
12680 // Currently non-resizable, becoming resizable
12681 if ( !isResizable && value !== false ) {
12682 this._makeResizable();
12686 if ( key === "title" ) {
12687 this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) );
12691 _size: function() {
12693 // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
12694 // divs will both have width and height set, so we need to reset them
12695 var nonContentHeight, minContentHeight, maxContentHeight,
12696 options = this.options;
12698 // Reset content sizing
12699 this.element.show().css( {
12706 if ( options.minWidth > options.width ) {
12707 options.width = options.minWidth;
12710 // Reset wrapper sizing
12711 // determine the height of all the non-content elements
12712 nonContentHeight = this.uiDialog.css( {
12714 width: options.width
12717 minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
12718 maxContentHeight = typeof options.maxHeight === "number" ?
12719 Math.max( 0, options.maxHeight - nonContentHeight ) :
12722 if ( options.height === "auto" ) {
12723 this.element.css( {
12724 minHeight: minContentHeight,
12725 maxHeight: maxContentHeight,
12729 this.element.height( Math.max( 0, options.height - nonContentHeight ) );
12732 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
12733 this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
12737 _blockFrames: function() {
12738 this.iframeBlocks = this.document.find( "iframe" ).map( function() {
12739 var iframe = $( this );
12741 return $( "<div>" )
12743 position: "absolute",
12744 width: iframe.outerWidth(),
12745 height: iframe.outerHeight()
12747 .appendTo( iframe.parent() )
12748 .offset( iframe.offset() )[ 0 ];
12752 _unblockFrames: function() {
12753 if ( this.iframeBlocks ) {
12754 this.iframeBlocks.remove();
12755 delete this.iframeBlocks;
12759 _allowInteraction: function( event ) {
12760 if ( $( event.target ).closest( ".ui-dialog" ).length ) {
12764 // TODO: Remove hack when datepicker implements
12765 // the .ui-front logic (#8989)
12766 return !!$( event.target ).closest( ".ui-datepicker" ).length;
12769 _createOverlay: function() {
12770 if ( !this.options.modal ) {
12774 // We use a delay in case the overlay is created from an
12775 // event that we're going to be cancelling (#2804)
12776 var isOpening = true;
12777 this._delay( function() {
12781 if ( !this.document.data( "ui-dialog-overlays" ) ) {
12783 // Prevent use of anchors and inputs
12784 // Using _on() for an event handler shared across many instances is
12785 // safe because the dialogs stack and must be closed in reverse order
12786 this._on( this.document, {
12787 focusin: function( event ) {
12792 if ( !this._allowInteraction( event ) ) {
12793 event.preventDefault();
12794 this._trackingInstances()[ 0 ]._focusTabbable();
12800 this.overlay = $( "<div>" )
12801 .appendTo( this._appendTo() );
12803 this._addClass( this.overlay, null, "ui-widget-overlay ui-front" );
12804 this._on( this.overlay, {
12805 mousedown: "_keepFocus"
12807 this.document.data( "ui-dialog-overlays",
12808 ( this.document.data( "ui-dialog-overlays" ) || 0 ) + 1 );
12811 _destroyOverlay: function() {
12812 if ( !this.options.modal ) {
12816 if ( this.overlay ) {
12817 var overlays = this.document.data( "ui-dialog-overlays" ) - 1;
12820 this._off( this.document, "focusin" );
12821 this.document.removeData( "ui-dialog-overlays" );
12823 this.document.data( "ui-dialog-overlays", overlays );
12826 this.overlay.remove();
12827 this.overlay = null;
12833 // TODO: switch return back to widget declaration at top of file when this is removed
12834 if ( $.uiBackCompat !== false ) {
12836 // Backcompat for dialogClass option
12837 $.widget( "ui.dialog", $.ui.dialog, {
12841 _createWrapper: function() {
12843 this.uiDialog.addClass( this.options.dialogClass );
12845 _setOption: function( key, value ) {
12846 if ( key === "dialogClass" ) {
12848 .removeClass( this.options.dialogClass )
12849 .addClass( value );
12851 this._superApply( arguments );
12856 var widgetsDialog = $.ui.dialog;
12860 * jQuery UI Droppable 1.12.1
12861 * http://jqueryui.com
12863 * Copyright jQuery Foundation and other contributors
12864 * Released under the MIT license.
12865 * http://jquery.org/license
12868 //>>label: Droppable
12869 //>>group: Interactions
12870 //>>description: Enables drop targets for draggable elements.
12871 //>>docs: http://api.jqueryui.com/droppable/
12872 //>>demos: http://jqueryui.com/droppable/
12876 $.widget( "ui.droppable", {
12878 widgetEventPrefix: "drop",
12884 tolerance: "intersect",
12893 _create: function() {
12899 this.isover = false;
12902 this.accept = $.isFunction( accept ) ? accept : function( d ) {
12903 return d.is( accept );
12906 this.proportions = function( /* valueToWrite */ ) {
12907 if ( arguments.length ) {
12909 // Store the droppable's proportions
12910 proportions = arguments[ 0 ];
12913 // Retrieve or derive the droppable's proportions
12914 return proportions ?
12917 width: this.element[ 0 ].offsetWidth,
12918 height: this.element[ 0 ].offsetHeight
12923 this._addToManager( o.scope );
12925 o.addClasses && this._addClass( "ui-droppable" );
12929 _addToManager: function( scope ) {
12931 // Add the reference and positions to the manager
12932 $.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || [];
12933 $.ui.ddmanager.droppables[ scope ].push( this );
12936 _splice: function( drop ) {
12938 for ( ; i < drop.length; i++ ) {
12939 if ( drop[ i ] === this ) {
12940 drop.splice( i, 1 );
12945 _destroy: function() {
12946 var drop = $.ui.ddmanager.droppables[ this.options.scope ];
12948 this._splice( drop );
12951 _setOption: function( key, value ) {
12953 if ( key === "accept" ) {
12954 this.accept = $.isFunction( value ) ? value : function( d ) {
12955 return d.is( value );
12957 } else if ( key === "scope" ) {
12958 var drop = $.ui.ddmanager.droppables[ this.options.scope ];
12960 this._splice( drop );
12961 this._addToManager( value );
12964 this._super( key, value );
12967 _activate: function( event ) {
12968 var draggable = $.ui.ddmanager.current;
12970 this._addActiveClass();
12972 this._trigger( "activate", event, this.ui( draggable ) );
12976 _deactivate: function( event ) {
12977 var draggable = $.ui.ddmanager.current;
12979 this._removeActiveClass();
12981 this._trigger( "deactivate", event, this.ui( draggable ) );
12985 _over: function( event ) {
12987 var draggable = $.ui.ddmanager.current;
12989 // Bail if draggable and droppable are same element
12990 if ( !draggable || ( draggable.currentItem ||
12991 draggable.element )[ 0 ] === this.element[ 0 ] ) {
12995 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem ||
12996 draggable.element ) ) ) {
12997 this._addHoverClass();
12998 this._trigger( "over", event, this.ui( draggable ) );
13003 _out: function( event ) {
13005 var draggable = $.ui.ddmanager.current;
13007 // Bail if draggable and droppable are same element
13008 if ( !draggable || ( draggable.currentItem ||
13009 draggable.element )[ 0 ] === this.element[ 0 ] ) {
13013 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem ||
13014 draggable.element ) ) ) {
13015 this._removeHoverClass();
13016 this._trigger( "out", event, this.ui( draggable ) );
13021 _drop: function( event, custom ) {
13023 var draggable = custom || $.ui.ddmanager.current,
13024 childrenIntersection = false;
13026 // Bail if draggable and droppable are same element
13027 if ( !draggable || ( draggable.currentItem ||
13028 draggable.element )[ 0 ] === this.element[ 0 ] ) {
13033 .find( ":data(ui-droppable)" )
13034 .not( ".ui-draggable-dragging" )
13035 .each( function() {
13036 var inst = $( this ).droppable( "instance" );
13038 inst.options.greedy &&
13039 !inst.options.disabled &&
13040 inst.options.scope === draggable.options.scope &&
13042 inst.element[ 0 ], ( draggable.currentItem || draggable.element )
13046 $.extend( inst, { offset: inst.element.offset() } ),
13047 inst.options.tolerance, event
13050 childrenIntersection = true;
13053 if ( childrenIntersection ) {
13057 if ( this.accept.call( this.element[ 0 ],
13058 ( draggable.currentItem || draggable.element ) ) ) {
13059 this._removeActiveClass();
13060 this._removeHoverClass();
13062 this._trigger( "drop", event, this.ui( draggable ) );
13063 return this.element;
13070 ui: function( c ) {
13072 draggable: ( c.currentItem || c.element ),
13074 position: c.position,
13075 offset: c.positionAbs
13079 // Extension points just to make backcompat sane and avoid duplicating logic
13080 // TODO: Remove in 1.13 along with call to it below
13081 _addHoverClass: function() {
13082 this._addClass( "ui-droppable-hover" );
13085 _removeHoverClass: function() {
13086 this._removeClass( "ui-droppable-hover" );
13089 _addActiveClass: function() {
13090 this._addClass( "ui-droppable-active" );
13093 _removeActiveClass: function() {
13094 this._removeClass( "ui-droppable-active" );
13098 var intersect = $.ui.intersect = ( function() {
13099 function isOverAxis( x, reference, size ) {
13100 return ( x >= reference ) && ( x < ( reference + size ) );
13103 return function( draggable, droppable, toleranceMode, event ) {
13105 if ( !droppable.offset ) {
13109 var x1 = ( draggable.positionAbs ||
13110 draggable.position.absolute ).left + draggable.margins.left,
13111 y1 = ( draggable.positionAbs ||
13112 draggable.position.absolute ).top + draggable.margins.top,
13113 x2 = x1 + draggable.helperProportions.width,
13114 y2 = y1 + draggable.helperProportions.height,
13115 l = droppable.offset.left,
13116 t = droppable.offset.top,
13117 r = l + droppable.proportions().width,
13118 b = t + droppable.proportions().height;
13120 switch ( toleranceMode ) {
13122 return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b );
13124 return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half
13125 x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half
13126 t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half
13127 y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half
13129 return isOverAxis( event.pageY, t, droppable.proportions().height ) &&
13130 isOverAxis( event.pageX, l, droppable.proportions().width );
13133 ( y1 >= t && y1 <= b ) || // Top edge touching
13134 ( y2 >= t && y2 <= b ) || // Bottom edge touching
13135 ( y1 < t && y2 > b ) // Surrounded vertically
13137 ( x1 >= l && x1 <= r ) || // Left edge touching
13138 ( x2 >= l && x2 <= r ) || // Right edge touching
13139 ( x1 < l && x2 > r ) // Surrounded horizontally
13148 This manager tracks offsets of draggables and droppables
13152 droppables: { "default": [] },
13153 prepareOffsets: function( t, event ) {
13156 m = $.ui.ddmanager.droppables[ t.options.scope ] || [],
13157 type = event ? event.type : null, // workaround for #2317
13158 list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack();
13160 droppablesLoop: for ( i = 0; i < m.length; i++ ) {
13162 // No disabled and non-accepted
13163 if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ],
13164 ( t.currentItem || t.element ) ) ) ) {
13168 // Filter out elements in the current dragged item
13169 for ( j = 0; j < list.length; j++ ) {
13170 if ( list[ j ] === m[ i ].element[ 0 ] ) {
13171 m[ i ].proportions().height = 0;
13172 continue droppablesLoop;
13176 m[ i ].visible = m[ i ].element.css( "display" ) !== "none";
13177 if ( !m[ i ].visible ) {
13181 // Activate the droppable if used directly from draggables
13182 if ( type === "mousedown" ) {
13183 m[ i ]._activate.call( m[ i ], event );
13186 m[ i ].offset = m[ i ].element.offset();
13187 m[ i ].proportions( {
13188 width: m[ i ].element[ 0 ].offsetWidth,
13189 height: m[ i ].element[ 0 ].offsetHeight
13195 drop: function( draggable, event ) {
13197 var dropped = false;
13199 // Create a copy of the droppables in case the list changes during the drop (#9116)
13200 $.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() {
13202 if ( !this.options ) {
13205 if ( !this.options.disabled && this.visible &&
13206 intersect( draggable, this, this.options.tolerance, event ) ) {
13207 dropped = this._drop.call( this, event ) || dropped;
13210 if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ],
13211 ( draggable.currentItem || draggable.element ) ) ) {
13213 this.isover = false;
13214 this._deactivate.call( this, event );
13221 dragStart: function( draggable, event ) {
13223 // Listen for scrolling so that if the dragging causes scrolling the position of the
13224 // droppables can be recalculated (see #5003)
13225 draggable.element.parentsUntil( "body" ).on( "scroll.droppable", function() {
13226 if ( !draggable.options.refreshPositions ) {
13227 $.ui.ddmanager.prepareOffsets( draggable, event );
13231 drag: function( draggable, event ) {
13233 // If you have a highly dynamic page, you might try this option. It renders positions
13234 // every time you move the mouse.
13235 if ( draggable.options.refreshPositions ) {
13236 $.ui.ddmanager.prepareOffsets( draggable, event );
13239 // Run through all droppables and check their positions based on specific tolerance options
13240 $.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() {
13242 if ( this.options.disabled || this.greedyChild || !this.visible ) {
13246 var parentInstance, scope, parent,
13247 intersects = intersect( draggable, this, this.options.tolerance, event ),
13248 c = !intersects && this.isover ?
13250 ( intersects && !this.isover ? "isover" : null );
13255 if ( this.options.greedy ) {
13257 // find droppable parents with same scope
13258 scope = this.options.scope;
13259 parent = this.element.parents( ":data(ui-droppable)" ).filter( function() {
13260 return $( this ).droppable( "instance" ).options.scope === scope;
13263 if ( parent.length ) {
13264 parentInstance = $( parent[ 0 ] ).droppable( "instance" );
13265 parentInstance.greedyChild = ( c === "isover" );
13269 // We just moved into a greedy child
13270 if ( parentInstance && c === "isover" ) {
13271 parentInstance.isover = false;
13272 parentInstance.isout = true;
13273 parentInstance._out.call( parentInstance, event );
13277 this[ c === "isout" ? "isover" : "isout" ] = false;
13278 this[ c === "isover" ? "_over" : "_out" ].call( this, event );
13280 // We just moved out of a greedy child
13281 if ( parentInstance && c === "isout" ) {
13282 parentInstance.isout = false;
13283 parentInstance.isover = true;
13284 parentInstance._over.call( parentInstance, event );
13289 dragStop: function( draggable, event ) {
13290 draggable.element.parentsUntil( "body" ).off( "scroll.droppable" );
13292 // Call prepareOffsets one final time since IE does not fire return scroll events when
13293 // overflow was caused by drag (see #5003)
13294 if ( !draggable.options.refreshPositions ) {
13295 $.ui.ddmanager.prepareOffsets( draggable, event );
13301 // TODO: switch return back to widget declaration at top of file when this is removed
13302 if ( $.uiBackCompat !== false ) {
13304 // Backcompat for activeClass and hoverClass options
13305 $.widget( "ui.droppable", $.ui.droppable, {
13310 _addActiveClass: function() {
13312 if ( this.options.activeClass ) {
13313 this.element.addClass( this.options.activeClass );
13316 _removeActiveClass: function() {
13318 if ( this.options.activeClass ) {
13319 this.element.removeClass( this.options.activeClass );
13322 _addHoverClass: function() {
13324 if ( this.options.hoverClass ) {
13325 this.element.addClass( this.options.hoverClass );
13328 _removeHoverClass: function() {
13330 if ( this.options.hoverClass ) {
13331 this.element.removeClass( this.options.hoverClass );
13337 var widgetsDroppable = $.ui.droppable;
13341 * jQuery UI Progressbar 1.12.1
13342 * http://jqueryui.com
13344 * Copyright jQuery Foundation and other contributors
13345 * Released under the MIT license.
13346 * http://jquery.org/license
13349 //>>label: Progressbar
13351 // jscs:disable maximumLineLength
13352 //>>description: Displays a status indicator for loading state, standard percentage, and other progress indicators.
13353 // jscs:enable maximumLineLength
13354 //>>docs: http://api.jqueryui.com/progressbar/
13355 //>>demos: http://jqueryui.com/progressbar/
13356 //>>css.structure: ../../themes/base/core.css
13357 //>>css.structure: ../../themes/base/progressbar.css
13358 //>>css.theme: ../../themes/base/theme.css
13362 var widgetsProgressbar = $.widget( "ui.progressbar", {
13366 "ui-progressbar": "ui-corner-all",
13367 "ui-progressbar-value": "ui-corner-left",
13368 "ui-progressbar-complete": "ui-corner-right"
13379 _create: function() {
13381 // Constrain initial value
13382 this.oldValue = this.options.value = this._constrainedValue();
13384 this.element.attr( {
13386 // Only set static values; aria-valuenow and aria-valuemax are
13387 // set inside _refreshValue()
13388 role: "progressbar",
13389 "aria-valuemin": this.min
13391 this._addClass( "ui-progressbar", "ui-widget ui-widget-content" );
13393 this.valueDiv = $( "<div>" ).appendTo( this.element );
13394 this._addClass( this.valueDiv, "ui-progressbar-value", "ui-widget-header" );
13395 this._refreshValue();
13398 _destroy: function() {
13399 this.element.removeAttr( "role aria-valuemin aria-valuemax aria-valuenow" );
13401 this.valueDiv.remove();
13404 value: function( newValue ) {
13405 if ( newValue === undefined ) {
13406 return this.options.value;
13409 this.options.value = this._constrainedValue( newValue );
13410 this._refreshValue();
13413 _constrainedValue: function( newValue ) {
13414 if ( newValue === undefined ) {
13415 newValue = this.options.value;
13418 this.indeterminate = newValue === false;
13421 if ( typeof newValue !== "number" ) {
13425 return this.indeterminate ? false :
13426 Math.min( this.options.max, Math.max( this.min, newValue ) );
13429 _setOptions: function( options ) {
13431 // Ensure "value" option is set after other values (like max)
13432 var value = options.value;
13433 delete options.value;
13435 this._super( options );
13437 this.options.value = this._constrainedValue( value );
13438 this._refreshValue();
13441 _setOption: function( key, value ) {
13442 if ( key === "max" ) {
13444 // Don't allow a max less than min
13445 value = Math.max( this.min, value );
13447 this._super( key, value );
13450 _setOptionDisabled: function( value ) {
13451 this._super( value );
13453 this.element.attr( "aria-disabled", value );
13454 this._toggleClass( null, "ui-state-disabled", !!value );
13457 _percentage: function() {
13458 return this.indeterminate ?
13460 100 * ( this.options.value - this.min ) / ( this.options.max - this.min );
13463 _refreshValue: function() {
13464 var value = this.options.value,
13465 percentage = this._percentage();
13468 .toggle( this.indeterminate || value > this.min )
13469 .width( percentage.toFixed( 0 ) + "%" );
13472 ._toggleClass( this.valueDiv, "ui-progressbar-complete", null,
13473 value === this.options.max )
13474 ._toggleClass( "ui-progressbar-indeterminate", null, this.indeterminate );
13476 if ( this.indeterminate ) {
13477 this.element.removeAttr( "aria-valuenow" );
13478 if ( !this.overlayDiv ) {
13479 this.overlayDiv = $( "<div>" ).appendTo( this.valueDiv );
13480 this._addClass( this.overlayDiv, "ui-progressbar-overlay" );
13483 this.element.attr( {
13484 "aria-valuemax": this.options.max,
13485 "aria-valuenow": value
13487 if ( this.overlayDiv ) {
13488 this.overlayDiv.remove();
13489 this.overlayDiv = null;
13493 if ( this.oldValue !== value ) {
13494 this.oldValue = value;
13495 this._trigger( "change" );
13497 if ( value === this.options.max ) {
13498 this._trigger( "complete" );
13505 * jQuery UI Selectable 1.12.1
13506 * http://jqueryui.com
13508 * Copyright jQuery Foundation and other contributors
13509 * Released under the MIT license.
13510 * http://jquery.org/license
13513 //>>label: Selectable
13514 //>>group: Interactions
13515 //>>description: Allows groups of elements to be selected with the mouse.
13516 //>>docs: http://api.jqueryui.com/selectable/
13517 //>>demos: http://jqueryui.com/selectable/
13518 //>>css.structure: ../../themes/base/selectable.css
13522 var widgetsSelectable = $.widget( "ui.selectable", $.ui.mouse, {
13529 tolerance: "touch",
13539 _create: function() {
13542 this._addClass( "ui-selectable" );
13544 this.dragged = false;
13546 // Cache selectee children based on filter
13547 this.refresh = function() {
13548 that.elementPos = $( that.element[ 0 ] ).offset();
13549 that.selectees = $( that.options.filter, that.element[ 0 ] );
13550 that._addClass( that.selectees, "ui-selectee" );
13551 that.selectees.each( function() {
13552 var $this = $( this ),
13553 selecteeOffset = $this.offset(),
13555 left: selecteeOffset.left - that.elementPos.left,
13556 top: selecteeOffset.top - that.elementPos.top
13558 $.data( this, "selectable-item", {
13563 right: pos.left + $this.outerWidth(),
13564 bottom: pos.top + $this.outerHeight(),
13565 startselected: false,
13566 selected: $this.hasClass( "ui-selected" ),
13567 selecting: $this.hasClass( "ui-selecting" ),
13568 unselecting: $this.hasClass( "ui-unselecting" )
13576 this.helper = $( "<div>" );
13577 this._addClass( this.helper, "ui-selectable-helper" );
13580 _destroy: function() {
13581 this.selectees.removeData( "selectable-item" );
13582 this._mouseDestroy();
13585 _mouseStart: function( event ) {
13587 options = this.options;
13589 this.opos = [ event.pageX, event.pageY ];
13590 this.elementPos = $( this.element[ 0 ] ).offset();
13592 if ( this.options.disabled ) {
13596 this.selectees = $( options.filter, this.element[ 0 ] );
13598 this._trigger( "start", event );
13600 $( options.appendTo ).append( this.helper );
13602 // position helper (lasso)
13604 "left": event.pageX,
13605 "top": event.pageY,
13610 if ( options.autoRefresh ) {
13614 this.selectees.filter( ".ui-selected" ).each( function() {
13615 var selectee = $.data( this, "selectable-item" );
13616 selectee.startselected = true;
13617 if ( !event.metaKey && !event.ctrlKey ) {
13618 that._removeClass( selectee.$element, "ui-selected" );
13619 selectee.selected = false;
13620 that._addClass( selectee.$element, "ui-unselecting" );
13621 selectee.unselecting = true;
13623 // selectable UNSELECTING callback
13624 that._trigger( "unselecting", event, {
13625 unselecting: selectee.element
13630 $( event.target ).parents().addBack().each( function() {
13632 selectee = $.data( this, "selectable-item" );
13634 doSelect = ( !event.metaKey && !event.ctrlKey ) ||
13635 !selectee.$element.hasClass( "ui-selected" );
13636 that._removeClass( selectee.$element, doSelect ? "ui-unselecting" : "ui-selected" )
13637 ._addClass( selectee.$element, doSelect ? "ui-selecting" : "ui-unselecting" );
13638 selectee.unselecting = !doSelect;
13639 selectee.selecting = doSelect;
13640 selectee.selected = doSelect;
13642 // selectable (UN)SELECTING callback
13644 that._trigger( "selecting", event, {
13645 selecting: selectee.element
13648 that._trigger( "unselecting", event, {
13649 unselecting: selectee.element
13658 _mouseDrag: function( event ) {
13660 this.dragged = true;
13662 if ( this.options.disabled ) {
13668 options = this.options,
13669 x1 = this.opos[ 0 ],
13670 y1 = this.opos[ 1 ],
13674 if ( x1 > x2 ) { tmp = x2; x2 = x1; x1 = tmp; }
13675 if ( y1 > y2 ) { tmp = y2; y2 = y1; y1 = tmp; }
13676 this.helper.css( { left: x1, top: y1, width: x2 - x1, height: y2 - y1 } );
13678 this.selectees.each( function() {
13679 var selectee = $.data( this, "selectable-item" ),
13683 //prevent helper from being selected if appendTo: selectable
13684 if ( !selectee || selectee.element === that.element[ 0 ] ) {
13688 offset.left = selectee.left + that.elementPos.left;
13689 offset.right = selectee.right + that.elementPos.left;
13690 offset.top = selectee.top + that.elementPos.top;
13691 offset.bottom = selectee.bottom + that.elementPos.top;
13693 if ( options.tolerance === "touch" ) {
13694 hit = ( !( offset.left > x2 || offset.right < x1 || offset.top > y2 ||
13695 offset.bottom < y1 ) );
13696 } else if ( options.tolerance === "fit" ) {
13697 hit = ( offset.left > x1 && offset.right < x2 && offset.top > y1 &&
13698 offset.bottom < y2 );
13704 if ( selectee.selected ) {
13705 that._removeClass( selectee.$element, "ui-selected" );
13706 selectee.selected = false;
13708 if ( selectee.unselecting ) {
13709 that._removeClass( selectee.$element, "ui-unselecting" );
13710 selectee.unselecting = false;
13712 if ( !selectee.selecting ) {
13713 that._addClass( selectee.$element, "ui-selecting" );
13714 selectee.selecting = true;
13716 // selectable SELECTING callback
13717 that._trigger( "selecting", event, {
13718 selecting: selectee.element
13724 if ( selectee.selecting ) {
13725 if ( ( event.metaKey || event.ctrlKey ) && selectee.startselected ) {
13726 that._removeClass( selectee.$element, "ui-selecting" );
13727 selectee.selecting = false;
13728 that._addClass( selectee.$element, "ui-selected" );
13729 selectee.selected = true;
13731 that._removeClass( selectee.$element, "ui-selecting" );
13732 selectee.selecting = false;
13733 if ( selectee.startselected ) {
13734 that._addClass( selectee.$element, "ui-unselecting" );
13735 selectee.unselecting = true;
13738 // selectable UNSELECTING callback
13739 that._trigger( "unselecting", event, {
13740 unselecting: selectee.element
13744 if ( selectee.selected ) {
13745 if ( !event.metaKey && !event.ctrlKey && !selectee.startselected ) {
13746 that._removeClass( selectee.$element, "ui-selected" );
13747 selectee.selected = false;
13749 that._addClass( selectee.$element, "ui-unselecting" );
13750 selectee.unselecting = true;
13752 // selectable UNSELECTING callback
13753 that._trigger( "unselecting", event, {
13754 unselecting: selectee.element
13764 _mouseStop: function( event ) {
13767 this.dragged = false;
13769 $( ".ui-unselecting", this.element[ 0 ] ).each( function() {
13770 var selectee = $.data( this, "selectable-item" );
13771 that._removeClass( selectee.$element, "ui-unselecting" );
13772 selectee.unselecting = false;
13773 selectee.startselected = false;
13774 that._trigger( "unselected", event, {
13775 unselected: selectee.element
13778 $( ".ui-selecting", this.element[ 0 ] ).each( function() {
13779 var selectee = $.data( this, "selectable-item" );
13780 that._removeClass( selectee.$element, "ui-selecting" )
13781 ._addClass( selectee.$element, "ui-selected" );
13782 selectee.selecting = false;
13783 selectee.selected = true;
13784 selectee.startselected = true;
13785 that._trigger( "selected", event, {
13786 selected: selectee.element
13789 this._trigger( "stop", event );
13791 this.helper.remove();
13800 * jQuery UI Selectmenu 1.12.1
13801 * http://jqueryui.com
13803 * Copyright jQuery Foundation and other contributors
13804 * Released under the MIT license.
13805 * http://jquery.org/license
13808 //>>label: Selectmenu
13810 // jscs:disable maximumLineLength
13811 //>>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.
13812 // jscs:enable maximumLineLength
13813 //>>docs: http://api.jqueryui.com/selectmenu/
13814 //>>demos: http://jqueryui.com/selectmenu/
13815 //>>css.structure: ../../themes/base/core.css
13816 //>>css.structure: ../../themes/base/selectmenu.css, ../../themes/base/button.css
13817 //>>css.theme: ../../themes/base/theme.css
13821 var widgetsSelectmenu = $.widget( "ui.selectmenu", [ $.ui.formResetMixin, {
13823 defaultElement: "<select>",
13827 "ui-selectmenu-button-open": "ui-corner-top",
13828 "ui-selectmenu-button-closed": "ui-corner-all"
13832 button: "ui-icon-triangle-1-s"
13849 _create: function() {
13850 var selectmenuId = this.element.uniqueId().attr( "id" );
13852 element: selectmenuId,
13853 button: selectmenuId + "-button",
13854 menu: selectmenuId + "-menu"
13857 this._drawButton();
13859 this._bindFormResetHandler();
13861 this._rendered = false;
13862 this.menuItems = $();
13865 _drawButton: function() {
13868 item = this._parseOption(
13869 this.element.find( "option:selected" ),
13870 this.element[ 0 ].selectedIndex
13873 // Associate existing label with the new button
13874 this.labels = this.element.labels().attr( "for", this.ids.button );
13875 this._on( this.labels, {
13876 click: function( event ) {
13877 this.button.focus();
13878 event.preventDefault();
13882 // Hide original select element
13883 this.element.hide();
13886 this.button = $( "<span>", {
13887 tabindex: this.options.disabled ? -1 : 0,
13888 id: this.ids.button,
13890 "aria-expanded": "false",
13891 "aria-autocomplete": "list",
13892 "aria-owns": this.ids.menu,
13893 "aria-haspopup": "true",
13894 title: this.element.attr( "title" )
13896 .insertAfter( this.element );
13898 this._addClass( this.button, "ui-selectmenu-button ui-selectmenu-button-closed",
13899 "ui-button ui-widget" );
13901 icon = $( "<span>" ).appendTo( this.button );
13902 this._addClass( icon, "ui-selectmenu-icon", "ui-icon " + this.options.icons.button );
13903 this.buttonItem = this._renderButtonItem( item )
13904 .appendTo( this.button );
13906 if ( this.options.width !== false ) {
13907 this._resizeButton();
13910 this._on( this.button, this._buttonEvents );
13911 this.button.one( "focusin", function() {
13913 // Delay rendering the menu items until the button receives focus.
13914 // The menu may have already been rendered via a programmatic open.
13915 if ( !that._rendered ) {
13916 that._refreshMenu();
13921 _drawMenu: function() {
13925 this.menu = $( "<ul>", {
13926 "aria-hidden": "true",
13927 "aria-labelledby": this.ids.button,
13932 this.menuWrap = $( "<div>" ).append( this.menu );
13933 this._addClass( this.menuWrap, "ui-selectmenu-menu", "ui-front" );
13934 this.menuWrap.appendTo( this._appendTo() );
13936 // Initialize menu widget
13937 this.menuInstance = this.menu
13940 "ui-menu": "ui-corner-bottom"
13943 select: function( event, ui ) {
13944 event.preventDefault();
13947 // If the item was selected via a click, the text selection
13948 // will be destroyed in IE
13949 that._setSelection();
13951 that._select( ui.item.data( "ui-selectmenu-item" ), event );
13953 focus: function( event, ui ) {
13954 var item = ui.item.data( "ui-selectmenu-item" );
13956 // Prevent inital focus from firing and check if its a newly focused item
13957 if ( that.focusIndex != null && item.index !== that.focusIndex ) {
13958 that._trigger( "focus", event, { item: item } );
13959 if ( !that.isOpen ) {
13960 that._select( item, event );
13963 that.focusIndex = item.index;
13965 that.button.attr( "aria-activedescendant",
13966 that.menuItems.eq( item.index ).attr( "id" ) );
13969 .menu( "instance" );
13971 // Don't close the menu on mouseleave
13972 this.menuInstance._off( this.menu, "mouseleave" );
13974 // Cancel the menu's collapseAll on document click
13975 this.menuInstance._closeOnDocumentClick = function() {
13979 // Selects often contain empty items, but never contain dividers
13980 this.menuInstance._isDivider = function() {
13985 refresh: function() {
13986 this._refreshMenu();
13987 this.buttonItem.replaceWith(
13988 this.buttonItem = this._renderButtonItem(
13990 // Fall back to an empty object in case there are no options
13991 this._getSelectedItem().data( "ui-selectmenu-item" ) || {}
13994 if ( this.options.width === null ) {
13995 this._resizeButton();
13999 _refreshMenu: function() {
14001 options = this.element.find( "option" );
14005 this._parseOptions( options );
14006 this._renderMenu( this.menu, this.items );
14008 this.menuInstance.refresh();
14009 this.menuItems = this.menu.find( "li" )
14010 .not( ".ui-selectmenu-optgroup" )
14011 .find( ".ui-menu-item-wrapper" );
14013 this._rendered = true;
14015 if ( !options.length ) {
14019 item = this._getSelectedItem();
14021 // Update the menu to have the correct item focused
14022 this.menuInstance.focus( null, item );
14023 this._setAria( item.data( "ui-selectmenu-item" ) );
14025 // Set disabled state
14026 this._setOption( "disabled", this.element.prop( "disabled" ) );
14029 open: function( event ) {
14030 if ( this.options.disabled ) {
14034 // If this is the first time the menu is being opened, render the items
14035 if ( !this._rendered ) {
14036 this._refreshMenu();
14039 // Menu clears focus on close, reset focus to selected item
14040 this._removeClass( this.menu.find( ".ui-state-active" ), null, "ui-state-active" );
14041 this.menuInstance.focus( null, this._getSelectedItem() );
14044 // If there are no options, don't open the menu
14045 if ( !this.menuItems.length ) {
14049 this.isOpen = true;
14050 this._toggleAttr();
14051 this._resizeMenu();
14054 this._on( this.document, this._documentClick );
14056 this._trigger( "open", event );
14059 _position: function() {
14060 this.menuWrap.position( $.extend( { of: this.button }, this.options.position ) );
14063 close: function( event ) {
14064 if ( !this.isOpen ) {
14068 this.isOpen = false;
14069 this._toggleAttr();
14072 this._off( this.document );
14074 this._trigger( "close", event );
14077 widget: function() {
14078 return this.button;
14081 menuWidget: function() {
14085 _renderButtonItem: function( item ) {
14086 var buttonItem = $( "<span>" );
14088 this._setText( buttonItem, item.label );
14089 this._addClass( buttonItem, "ui-selectmenu-text" );
14094 _renderMenu: function( ul, items ) {
14096 currentOptgroup = "";
14098 $.each( items, function( index, item ) {
14101 if ( item.optgroup !== currentOptgroup ) {
14103 text: item.optgroup
14105 that._addClass( li, "ui-selectmenu-optgroup", "ui-menu-divider" +
14106 ( item.element.parent( "optgroup" ).prop( "disabled" ) ?
14107 " ui-state-disabled" :
14112 currentOptgroup = item.optgroup;
14115 that._renderItemData( ul, item );
14119 _renderItemData: function( ul, item ) {
14120 return this._renderItem( ul, item ).data( "ui-selectmenu-item", item );
14123 _renderItem: function( ul, item ) {
14124 var li = $( "<li>" ),
14125 wrapper = $( "<div>", {
14126 title: item.element.attr( "title" )
14129 if ( item.disabled ) {
14130 this._addClass( li, null, "ui-state-disabled" );
14132 this._setText( wrapper, item.label );
14134 return li.append( wrapper ).appendTo( ul );
14137 _setText: function( element, value ) {
14139 element.text( value );
14141 element.html( " " );
14145 _move: function( direction, event ) {
14147 filter = ".ui-menu-item";
14149 if ( this.isOpen ) {
14150 item = this.menuItems.eq( this.focusIndex ).parent( "li" );
14152 item = this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" );
14153 filter += ":not(.ui-state-disabled)";
14156 if ( direction === "first" || direction === "last" ) {
14157 next = item[ direction === "first" ? "prevAll" : "nextAll" ]( filter ).eq( -1 );
14159 next = item[ direction + "All" ]( filter ).eq( 0 );
14162 if ( next.length ) {
14163 this.menuInstance.focus( event, next );
14167 _getSelectedItem: function() {
14168 return this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" );
14171 _toggle: function( event ) {
14172 this[ this.isOpen ? "close" : "open" ]( event );
14175 _setSelection: function() {
14178 if ( !this.range ) {
14182 if ( window.getSelection ) {
14183 selection = window.getSelection();
14184 selection.removeAllRanges();
14185 selection.addRange( this.range );
14189 this.range.select();
14193 // Setting the text selection kills the button focus in IE, but
14194 // restoring the focus doesn't kill the selection.
14195 this.button.focus();
14199 mousedown: function( event ) {
14200 if ( !this.isOpen ) {
14204 if ( !$( event.target ).closest( ".ui-selectmenu-menu, #" +
14205 $.ui.escapeSelector( this.ids.button ) ).length ) {
14206 this.close( event );
14213 // Prevent text selection from being reset when interacting with the selectmenu (#10144)
14214 mousedown: function() {
14217 if ( window.getSelection ) {
14218 selection = window.getSelection();
14219 if ( selection.rangeCount ) {
14220 this.range = selection.getRangeAt( 0 );
14225 this.range = document.selection.createRange();
14229 click: function( event ) {
14230 this._setSelection();
14231 this._toggle( event );
14234 keydown: function( event ) {
14235 var preventDefault = true;
14236 switch ( event.keyCode ) {
14237 case $.ui.keyCode.TAB:
14238 case $.ui.keyCode.ESCAPE:
14239 this.close( event );
14240 preventDefault = false;
14242 case $.ui.keyCode.ENTER:
14243 if ( this.isOpen ) {
14244 this._selectFocusedItem( event );
14247 case $.ui.keyCode.UP:
14248 if ( event.altKey ) {
14249 this._toggle( event );
14251 this._move( "prev", event );
14254 case $.ui.keyCode.DOWN:
14255 if ( event.altKey ) {
14256 this._toggle( event );
14258 this._move( "next", event );
14261 case $.ui.keyCode.SPACE:
14262 if ( this.isOpen ) {
14263 this._selectFocusedItem( event );
14265 this._toggle( event );
14268 case $.ui.keyCode.LEFT:
14269 this._move( "prev", event );
14271 case $.ui.keyCode.RIGHT:
14272 this._move( "next", event );
14274 case $.ui.keyCode.HOME:
14275 case $.ui.keyCode.PAGE_UP:
14276 this._move( "first", event );
14278 case $.ui.keyCode.END:
14279 case $.ui.keyCode.PAGE_DOWN:
14280 this._move( "last", event );
14283 this.menu.trigger( event );
14284 preventDefault = false;
14287 if ( preventDefault ) {
14288 event.preventDefault();
14293 _selectFocusedItem: function( event ) {
14294 var item = this.menuItems.eq( this.focusIndex ).parent( "li" );
14295 if ( !item.hasClass( "ui-state-disabled" ) ) {
14296 this._select( item.data( "ui-selectmenu-item" ), event );
14300 _select: function( item, event ) {
14301 var oldIndex = this.element[ 0 ].selectedIndex;
14303 // Change native select element
14304 this.element[ 0 ].selectedIndex = item.index;
14305 this.buttonItem.replaceWith( this.buttonItem = this._renderButtonItem( item ) );
14306 this._setAria( item );
14307 this._trigger( "select", event, { item: item } );
14309 if ( item.index !== oldIndex ) {
14310 this._trigger( "change", event, { item: item } );
14313 this.close( event );
14316 _setAria: function( item ) {
14317 var id = this.menuItems.eq( item.index ).attr( "id" );
14319 this.button.attr( {
14320 "aria-labelledby": id,
14321 "aria-activedescendant": id
14323 this.menu.attr( "aria-activedescendant", id );
14326 _setOption: function( key, value ) {
14327 if ( key === "icons" ) {
14328 var icon = this.button.find( "span.ui-icon" );
14329 this._removeClass( icon, null, this.options.icons.button )
14330 ._addClass( icon, null, value.button );
14333 this._super( key, value );
14335 if ( key === "appendTo" ) {
14336 this.menuWrap.appendTo( this._appendTo() );
14339 if ( key === "width" ) {
14340 this._resizeButton();
14344 _setOptionDisabled: function( value ) {
14345 this._super( value );
14347 this.menuInstance.option( "disabled", value );
14348 this.button.attr( "aria-disabled", value );
14349 this._toggleClass( this.button, null, "ui-state-disabled", value );
14351 this.element.prop( "disabled", value );
14353 this.button.attr( "tabindex", -1 );
14356 this.button.attr( "tabindex", 0 );
14360 _appendTo: function() {
14361 var element = this.options.appendTo;
14364 element = element.jquery || element.nodeType ?
14366 this.document.find( element ).eq( 0 );
14369 if ( !element || !element[ 0 ] ) {
14370 element = this.element.closest( ".ui-front, dialog" );
14373 if ( !element.length ) {
14374 element = this.document[ 0 ].body;
14380 _toggleAttr: function() {
14381 this.button.attr( "aria-expanded", this.isOpen );
14383 // We can't use two _toggleClass() calls here, because we need to make sure
14384 // we always remove classes first and add them second, otherwise if both classes have the
14385 // same theme class, it will be removed after we add it.
14386 this._removeClass( this.button, "ui-selectmenu-button-" +
14387 ( this.isOpen ? "closed" : "open" ) )
14388 ._addClass( this.button, "ui-selectmenu-button-" +
14389 ( this.isOpen ? "open" : "closed" ) )
14390 ._toggleClass( this.menuWrap, "ui-selectmenu-open", null, this.isOpen );
14392 this.menu.attr( "aria-hidden", !this.isOpen );
14395 _resizeButton: function() {
14396 var width = this.options.width;
14398 // For `width: false`, just remove inline style and stop
14399 if ( width === false ) {
14400 this.button.css( "width", "" );
14404 // For `width: null`, match the width of the original element
14405 if ( width === null ) {
14406 width = this.element.show().outerWidth();
14407 this.element.hide();
14410 this.button.outerWidth( width );
14413 _resizeMenu: function() {
14414 this.menu.outerWidth( Math.max(
14415 this.button.outerWidth(),
14418 // IE10 wraps long text (possibly a rounding bug)
14419 // so we add 1px to avoid the wrapping
14420 this.menu.width( "" ).outerWidth() + 1
14424 _getCreateOptions: function() {
14425 var options = this._super();
14427 options.disabled = this.element.prop( "disabled" );
14432 _parseOptions: function( options ) {
14435 options.each( function( index, item ) {
14436 data.push( that._parseOption( $( item ), index ) );
14441 _parseOption: function( option, index ) {
14442 var optgroup = option.parent( "optgroup" );
14447 value: option.val(),
14448 label: option.text(),
14449 optgroup: optgroup.attr( "label" ) || "",
14450 disabled: optgroup.prop( "disabled" ) || option.prop( "disabled" )
14454 _destroy: function() {
14455 this._unbindFormResetHandler();
14456 this.menuWrap.remove();
14457 this.button.remove();
14458 this.element.show();
14459 this.element.removeUniqueId();
14460 this.labels.attr( "for", this.ids.element );
14466 * jQuery UI Slider 1.12.1
14467 * http://jqueryui.com
14469 * Copyright jQuery Foundation and other contributors
14470 * Released under the MIT license.
14471 * http://jquery.org/license
14476 //>>description: Displays a flexible slider with ranges and accessibility via keyboard.
14477 //>>docs: http://api.jqueryui.com/slider/
14478 //>>demos: http://jqueryui.com/slider/
14479 //>>css.structure: ../../themes/base/core.css
14480 //>>css.structure: ../../themes/base/slider.css
14481 //>>css.theme: ../../themes/base/theme.css
14485 var widgetsSlider = $.widget( "ui.slider", $.ui.mouse, {
14487 widgetEventPrefix: "slide",
14492 "ui-slider": "ui-corner-all",
14493 "ui-slider-handle": "ui-corner-all",
14495 // Note: ui-widget-header isn't the most fittingly semantic framework class for this
14496 // element, but worked best visually with a variety of themes
14497 "ui-slider-range": "ui-corner-all ui-widget-header"
14502 orientation: "horizontal",
14515 // Number of pages in a slider
14516 // (how many times can you page up/down to go through the whole range)
14519 _create: function() {
14520 this._keySliding = false;
14521 this._mouseSliding = false;
14522 this._animateOff = true;
14523 this._handleIndex = null;
14524 this._detectOrientation();
14526 this._calculateNewMax();
14528 this._addClass( "ui-slider ui-slider-" + this.orientation,
14529 "ui-widget ui-widget-content" );
14533 this._animateOff = false;
14536 _refresh: function() {
14537 this._createRange();
14538 this._createHandles();
14539 this._setupEvents();
14540 this._refreshValue();
14543 _createHandles: function() {
14544 var i, handleCount,
14545 options = this.options,
14546 existingHandles = this.element.find( ".ui-slider-handle" ),
14547 handle = "<span tabindex='0'></span>",
14550 handleCount = ( options.values && options.values.length ) || 1;
14552 if ( existingHandles.length > handleCount ) {
14553 existingHandles.slice( handleCount ).remove();
14554 existingHandles = existingHandles.slice( 0, handleCount );
14557 for ( i = existingHandles.length; i < handleCount; i++ ) {
14558 handles.push( handle );
14561 this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
14563 this._addClass( this.handles, "ui-slider-handle", "ui-state-default" );
14565 this.handle = this.handles.eq( 0 );
14567 this.handles.each( function( i ) {
14569 .data( "ui-slider-handle-index", i )
14570 .attr( "tabIndex", 0 );
14574 _createRange: function() {
14575 var options = this.options;
14577 if ( options.range ) {
14578 if ( options.range === true ) {
14579 if ( !options.values ) {
14580 options.values = [ this._valueMin(), this._valueMin() ];
14581 } else if ( options.values.length && options.values.length !== 2 ) {
14582 options.values = [ options.values[ 0 ], options.values[ 0 ] ];
14583 } else if ( $.isArray( options.values ) ) {
14584 options.values = options.values.slice( 0 );
14588 if ( !this.range || !this.range.length ) {
14589 this.range = $( "<div>" )
14590 .appendTo( this.element );
14592 this._addClass( this.range, "ui-slider-range" );
14594 this._removeClass( this.range, "ui-slider-range-min ui-slider-range-max" );
14596 // Handle range switching from true to min/max
14602 if ( options.range === "min" || options.range === "max" ) {
14603 this._addClass( this.range, "ui-slider-range-" + options.range );
14606 if ( this.range ) {
14607 this.range.remove();
14613 _setupEvents: function() {
14614 this._off( this.handles );
14615 this._on( this.handles, this._handleEvents );
14616 this._hoverable( this.handles );
14617 this._focusable( this.handles );
14620 _destroy: function() {
14621 this.handles.remove();
14622 if ( this.range ) {
14623 this.range.remove();
14626 this._mouseDestroy();
14629 _mouseCapture: function( event ) {
14630 var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
14634 if ( o.disabled ) {
14638 this.elementSize = {
14639 width: this.element.outerWidth(),
14640 height: this.element.outerHeight()
14642 this.elementOffset = this.element.offset();
14644 position = { x: event.pageX, y: event.pageY };
14645 normValue = this._normValueFromMouse( position );
14646 distance = this._valueMax() - this._valueMin() + 1;
14647 this.handles.each( function( i ) {
14648 var thisDistance = Math.abs( normValue - that.values( i ) );
14649 if ( ( distance > thisDistance ) ||
14650 ( distance === thisDistance &&
14651 ( i === that._lastChangedValue || that.values( i ) === o.min ) ) ) {
14652 distance = thisDistance;
14653 closestHandle = $( this );
14658 allowed = this._start( event, index );
14659 if ( allowed === false ) {
14662 this._mouseSliding = true;
14664 this._handleIndex = index;
14666 this._addClass( closestHandle, null, "ui-state-active" );
14667 closestHandle.trigger( "focus" );
14669 offset = closestHandle.offset();
14670 mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
14671 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
14672 left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
14673 top: event.pageY - offset.top -
14674 ( closestHandle.height() / 2 ) -
14675 ( parseInt( closestHandle.css( "borderTopWidth" ), 10 ) || 0 ) -
14676 ( parseInt( closestHandle.css( "borderBottomWidth" ), 10 ) || 0 ) +
14677 ( parseInt( closestHandle.css( "marginTop" ), 10 ) || 0 )
14680 if ( !this.handles.hasClass( "ui-state-hover" ) ) {
14681 this._slide( event, index, normValue );
14683 this._animateOff = true;
14687 _mouseStart: function() {
14691 _mouseDrag: function( event ) {
14692 var position = { x: event.pageX, y: event.pageY },
14693 normValue = this._normValueFromMouse( position );
14695 this._slide( event, this._handleIndex, normValue );
14700 _mouseStop: function( event ) {
14701 this._removeClass( this.handles, null, "ui-state-active" );
14702 this._mouseSliding = false;
14704 this._stop( event, this._handleIndex );
14705 this._change( event, this._handleIndex );
14707 this._handleIndex = null;
14708 this._clickOffset = null;
14709 this._animateOff = false;
14714 _detectOrientation: function() {
14715 this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
14718 _normValueFromMouse: function( position ) {
14725 if ( this.orientation === "horizontal" ) {
14726 pixelTotal = this.elementSize.width;
14727 pixelMouse = position.x - this.elementOffset.left -
14728 ( this._clickOffset ? this._clickOffset.left : 0 );
14730 pixelTotal = this.elementSize.height;
14731 pixelMouse = position.y - this.elementOffset.top -
14732 ( this._clickOffset ? this._clickOffset.top : 0 );
14735 percentMouse = ( pixelMouse / pixelTotal );
14736 if ( percentMouse > 1 ) {
14739 if ( percentMouse < 0 ) {
14742 if ( this.orientation === "vertical" ) {
14743 percentMouse = 1 - percentMouse;
14746 valueTotal = this._valueMax() - this._valueMin();
14747 valueMouse = this._valueMin() + percentMouse * valueTotal;
14749 return this._trimAlignValue( valueMouse );
14752 _uiHash: function( index, value, values ) {
14754 handle: this.handles[ index ],
14755 handleIndex: index,
14756 value: value !== undefined ? value : this.value()
14759 if ( this._hasMultipleValues() ) {
14760 uiHash.value = value !== undefined ? value : this.values( index );
14761 uiHash.values = values || this.values();
14767 _hasMultipleValues: function() {
14768 return this.options.values && this.options.values.length;
14771 _start: function( event, index ) {
14772 return this._trigger( "start", event, this._uiHash( index ) );
14775 _slide: function( event, index, newVal ) {
14776 var allowed, otherVal,
14777 currentValue = this.value(),
14778 newValues = this.values();
14780 if ( this._hasMultipleValues() ) {
14781 otherVal = this.values( index ? 0 : 1 );
14782 currentValue = this.values( index );
14784 if ( this.options.values.length === 2 && this.options.range === true ) {
14785 newVal = index === 0 ? Math.min( otherVal, newVal ) : Math.max( otherVal, newVal );
14788 newValues[ index ] = newVal;
14791 if ( newVal === currentValue ) {
14795 allowed = this._trigger( "slide", event, this._uiHash( index, newVal, newValues ) );
14797 // A slide can be canceled by returning false from the slide callback
14798 if ( allowed === false ) {
14802 if ( this._hasMultipleValues() ) {
14803 this.values( index, newVal );
14805 this.value( newVal );
14809 _stop: function( event, index ) {
14810 this._trigger( "stop", event, this._uiHash( index ) );
14813 _change: function( event, index ) {
14814 if ( !this._keySliding && !this._mouseSliding ) {
14816 //store the last changed value index for reference when handles overlap
14817 this._lastChangedValue = index;
14818 this._trigger( "change", event, this._uiHash( index ) );
14822 value: function( newValue ) {
14823 if ( arguments.length ) {
14824 this.options.value = this._trimAlignValue( newValue );
14825 this._refreshValue();
14826 this._change( null, 0 );
14830 return this._value();
14833 values: function( index, newValue ) {
14838 if ( arguments.length > 1 ) {
14839 this.options.values[ index ] = this._trimAlignValue( newValue );
14840 this._refreshValue();
14841 this._change( null, index );
14845 if ( arguments.length ) {
14846 if ( $.isArray( arguments[ 0 ] ) ) {
14847 vals = this.options.values;
14848 newValues = arguments[ 0 ];
14849 for ( i = 0; i < vals.length; i += 1 ) {
14850 vals[ i ] = this._trimAlignValue( newValues[ i ] );
14851 this._change( null, i );
14853 this._refreshValue();
14855 if ( this._hasMultipleValues() ) {
14856 return this._values( index );
14858 return this.value();
14862 return this._values();
14866 _setOption: function( key, value ) {
14870 if ( key === "range" && this.options.range === true ) {
14871 if ( value === "min" ) {
14872 this.options.value = this._values( 0 );
14873 this.options.values = null;
14874 } else if ( value === "max" ) {
14875 this.options.value = this._values( this.options.values.length - 1 );
14876 this.options.values = null;
14880 if ( $.isArray( this.options.values ) ) {
14881 valsLength = this.options.values.length;
14884 this._super( key, value );
14887 case "orientation":
14888 this._detectOrientation();
14889 this._removeClass( "ui-slider-horizontal ui-slider-vertical" )
14890 ._addClass( "ui-slider-" + this.orientation );
14891 this._refreshValue();
14892 if ( this.options.range ) {
14893 this._refreshRange( value );
14896 // Reset positioning from previous orientation
14897 this.handles.css( value === "horizontal" ? "bottom" : "left", "" );
14900 this._animateOff = true;
14901 this._refreshValue();
14902 this._change( null, 0 );
14903 this._animateOff = false;
14906 this._animateOff = true;
14907 this._refreshValue();
14909 // Start from the last handle to prevent unreachable handles (#9046)
14910 for ( i = valsLength - 1; i >= 0; i-- ) {
14911 this._change( null, i );
14913 this._animateOff = false;
14918 this._animateOff = true;
14919 this._calculateNewMax();
14920 this._refreshValue();
14921 this._animateOff = false;
14924 this._animateOff = true;
14926 this._animateOff = false;
14931 _setOptionDisabled: function( value ) {
14932 this._super( value );
14934 this._toggleClass( null, "ui-state-disabled", !!value );
14937 //internal value getter
14938 // _value() returns value trimmed by min and max, aligned by step
14939 _value: function() {
14940 var val = this.options.value;
14941 val = this._trimAlignValue( val );
14946 //internal values getter
14947 // _values() returns array of values trimmed by min and max, aligned by step
14948 // _values( index ) returns single value trimmed by min and max, aligned by step
14949 _values: function( index ) {
14954 if ( arguments.length ) {
14955 val = this.options.values[ index ];
14956 val = this._trimAlignValue( val );
14959 } else if ( this._hasMultipleValues() ) {
14961 // .slice() creates a copy of the array
14962 // this copy gets trimmed by min and max and then returned
14963 vals = this.options.values.slice();
14964 for ( i = 0; i < vals.length; i += 1 ) {
14965 vals[ i ] = this._trimAlignValue( vals[ i ] );
14974 // Returns the step-aligned value that val is closest to, between (inclusive) min and max
14975 _trimAlignValue: function( val ) {
14976 if ( val <= this._valueMin() ) {
14977 return this._valueMin();
14979 if ( val >= this._valueMax() ) {
14980 return this._valueMax();
14982 var step = ( this.options.step > 0 ) ? this.options.step : 1,
14983 valModStep = ( val - this._valueMin() ) % step,
14984 alignValue = val - valModStep;
14986 if ( Math.abs( valModStep ) * 2 >= step ) {
14987 alignValue += ( valModStep > 0 ) ? step : ( -step );
14990 // Since JavaScript has problems with large floats, round
14991 // the final value to 5 digits after the decimal point (see #4124)
14992 return parseFloat( alignValue.toFixed( 5 ) );
14995 _calculateNewMax: function() {
14996 var max = this.options.max,
14997 min = this._valueMin(),
14998 step = this.options.step,
14999 aboveMin = Math.round( ( max - min ) / step ) * step;
15000 max = aboveMin + min;
15001 if ( max > this.options.max ) {
15003 //If max is not divisible by step, rounding off may increase its value
15006 this.max = parseFloat( max.toFixed( this._precision() ) );
15009 _precision: function() {
15010 var precision = this._precisionOf( this.options.step );
15011 if ( this.options.min !== null ) {
15012 precision = Math.max( precision, this._precisionOf( this.options.min ) );
15017 _precisionOf: function( num ) {
15018 var str = num.toString(),
15019 decimal = str.indexOf( "." );
15020 return decimal === -1 ? 0 : str.length - decimal - 1;
15023 _valueMin: function() {
15024 return this.options.min;
15027 _valueMax: function() {
15031 _refreshRange: function( orientation ) {
15032 if ( orientation === "vertical" ) {
15033 this.range.css( { "width": "", "left": "" } );
15035 if ( orientation === "horizontal" ) {
15036 this.range.css( { "height": "", "bottom": "" } );
15040 _refreshValue: function() {
15041 var lastValPercent, valPercent, value, valueMin, valueMax,
15042 oRange = this.options.range,
15045 animate = ( !this._animateOff ) ? o.animate : false,
15048 if ( this._hasMultipleValues() ) {
15049 this.handles.each( function( i ) {
15050 valPercent = ( that.values( i ) - that._valueMin() ) / ( that._valueMax() -
15051 that._valueMin() ) * 100;
15052 _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
15053 $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
15054 if ( that.options.range === true ) {
15055 if ( that.orientation === "horizontal" ) {
15057 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
15058 left: valPercent + "%"
15062 that.range[ animate ? "animate" : "css" ]( {
15063 width: ( valPercent - lastValPercent ) + "%"
15066 duration: o.animate
15071 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
15072 bottom: ( valPercent ) + "%"
15076 that.range[ animate ? "animate" : "css" ]( {
15077 height: ( valPercent - lastValPercent ) + "%"
15080 duration: o.animate
15085 lastValPercent = valPercent;
15088 value = this.value();
15089 valueMin = this._valueMin();
15090 valueMax = this._valueMax();
15091 valPercent = ( valueMax !== valueMin ) ?
15092 ( value - valueMin ) / ( valueMax - valueMin ) * 100 :
15094 _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
15095 this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
15097 if ( oRange === "min" && this.orientation === "horizontal" ) {
15098 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
15099 width: valPercent + "%"
15102 if ( oRange === "max" && this.orientation === "horizontal" ) {
15103 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
15104 width: ( 100 - valPercent ) + "%"
15107 if ( oRange === "min" && this.orientation === "vertical" ) {
15108 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
15109 height: valPercent + "%"
15112 if ( oRange === "max" && this.orientation === "vertical" ) {
15113 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
15114 height: ( 100 - valPercent ) + "%"
15121 keydown: function( event ) {
15122 var allowed, curVal, newVal, step,
15123 index = $( event.target ).data( "ui-slider-handle-index" );
15125 switch ( event.keyCode ) {
15126 case $.ui.keyCode.HOME:
15127 case $.ui.keyCode.END:
15128 case $.ui.keyCode.PAGE_UP:
15129 case $.ui.keyCode.PAGE_DOWN:
15130 case $.ui.keyCode.UP:
15131 case $.ui.keyCode.RIGHT:
15132 case $.ui.keyCode.DOWN:
15133 case $.ui.keyCode.LEFT:
15134 event.preventDefault();
15135 if ( !this._keySliding ) {
15136 this._keySliding = true;
15137 this._addClass( $( event.target ), null, "ui-state-active" );
15138 allowed = this._start( event, index );
15139 if ( allowed === false ) {
15146 step = this.options.step;
15147 if ( this._hasMultipleValues() ) {
15148 curVal = newVal = this.values( index );
15150 curVal = newVal = this.value();
15153 switch ( event.keyCode ) {
15154 case $.ui.keyCode.HOME:
15155 newVal = this._valueMin();
15157 case $.ui.keyCode.END:
15158 newVal = this._valueMax();
15160 case $.ui.keyCode.PAGE_UP:
15161 newVal = this._trimAlignValue(
15162 curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages )
15165 case $.ui.keyCode.PAGE_DOWN:
15166 newVal = this._trimAlignValue(
15167 curVal - ( ( this._valueMax() - this._valueMin() ) / this.numPages ) );
15169 case $.ui.keyCode.UP:
15170 case $.ui.keyCode.RIGHT:
15171 if ( curVal === this._valueMax() ) {
15174 newVal = this._trimAlignValue( curVal + step );
15176 case $.ui.keyCode.DOWN:
15177 case $.ui.keyCode.LEFT:
15178 if ( curVal === this._valueMin() ) {
15181 newVal = this._trimAlignValue( curVal - step );
15185 this._slide( event, index, newVal );
15187 keyup: function( event ) {
15188 var index = $( event.target ).data( "ui-slider-handle-index" );
15190 if ( this._keySliding ) {
15191 this._keySliding = false;
15192 this._stop( event, index );
15193 this._change( event, index );
15194 this._removeClass( $( event.target ), null, "ui-state-active" );
15202 * jQuery UI Sortable 1.12.1
15203 * http://jqueryui.com
15205 * Copyright jQuery Foundation and other contributors
15206 * Released under the MIT license.
15207 * http://jquery.org/license
15210 //>>label: Sortable
15211 //>>group: Interactions
15212 //>>description: Enables items in a list to be sorted using the mouse.
15213 //>>docs: http://api.jqueryui.com/sortable/
15214 //>>demos: http://jqueryui.com/sortable/
15215 //>>css.structure: ../../themes/base/sortable.css
15219 var widgetsSortable = $.widget( "ui.sortable", $.ui.mouse, {
15221 widgetEventPrefix: "sort",
15224 appendTo: "parent",
15226 connectWith: false,
15227 containment: false,
15231 forcePlaceholderSize: false,
15232 forceHelperSize: false,
15235 helper: "original",
15238 placeholder: false,
15241 scrollSensitivity: 20,
15244 tolerance: "intersect",
15262 _isOverAxis: function( x, reference, size ) {
15263 return ( x >= reference ) && ( x < ( reference + size ) );
15266 _isFloating: function( item ) {
15267 return ( /left|right/ ).test( item.css( "float" ) ) ||
15268 ( /inline|table-cell/ ).test( item.css( "display" ) );
15271 _create: function() {
15272 this.containerCache = {};
15273 this._addClass( "ui-sortable" );
15278 //Let's determine the parent's offset
15279 this.offset = this.element.offset();
15281 //Initialize mouse events for interaction
15284 this._setHandleClassName();
15286 //We're ready to go
15291 _setOption: function( key, value ) {
15292 this._super( key, value );
15294 if ( key === "handle" ) {
15295 this._setHandleClassName();
15299 _setHandleClassName: function() {
15301 this._removeClass( this.element.find( ".ui-sortable-handle" ), "ui-sortable-handle" );
15302 $.each( this.items, function() {
15304 this.instance.options.handle ?
15305 this.item.find( this.instance.options.handle ) :
15307 "ui-sortable-handle"
15312 _destroy: function() {
15313 this._mouseDestroy();
15315 for ( var i = this.items.length - 1; i >= 0; i-- ) {
15316 this.items[ i ].item.removeData( this.widgetName + "-item" );
15322 _mouseCapture: function( event, overrideHandle ) {
15323 var currentItem = null,
15324 validHandle = false,
15327 if ( this.reverting ) {
15331 if ( this.options.disabled || this.options.type === "static" ) {
15335 //We have to refresh the items data once first
15336 this._refreshItems( event );
15338 //Find out if the clicked node (or one of its parents) is a actual item in this.items
15339 $( event.target ).parents().each( function() {
15340 if ( $.data( this, that.widgetName + "-item" ) === that ) {
15341 currentItem = $( this );
15345 if ( $.data( event.target, that.widgetName + "-item" ) === that ) {
15346 currentItem = $( event.target );
15349 if ( !currentItem ) {
15352 if ( this.options.handle && !overrideHandle ) {
15353 $( this.options.handle, currentItem ).find( "*" ).addBack().each( function() {
15354 if ( this === event.target ) {
15355 validHandle = true;
15358 if ( !validHandle ) {
15363 this.currentItem = currentItem;
15364 this._removeCurrentsFromItems();
15369 _mouseStart: function( event, overrideHandle, noActivation ) {
15374 this.currentContainer = this;
15376 //We only need to call refreshPositions, because the refreshItems call has been moved to
15378 this.refreshPositions();
15380 //Create and append the visible helper
15381 this.helper = this._createHelper( event );
15383 //Cache the helper size
15384 this._cacheHelperProportions();
15387 * - Position generation -
15388 * This block generates everything position related - it's the core of draggables.
15391 //Cache the margins of the original element
15392 this._cacheMargins();
15394 //Get the next scrolling parent
15395 this.scrollParent = this.helper.scrollParent();
15397 //The element's absolute position on the page minus margins
15398 this.offset = this.currentItem.offset();
15400 top: this.offset.top - this.margins.top,
15401 left: this.offset.left - this.margins.left
15404 $.extend( this.offset, {
15405 click: { //Where the click happened, relative to the element
15406 left: event.pageX - this.offset.left,
15407 top: event.pageY - this.offset.top
15409 parent: this._getParentOffset(),
15411 // This is a relative to absolute position minus the actual position calculation -
15412 // only used for relative positioned helper
15413 relative: this._getRelativeOffset()
15416 // Only after we got the offset, we can change the helper's position to absolute
15417 // TODO: Still need to figure out a way to make relative sorting possible
15418 this.helper.css( "position", "absolute" );
15419 this.cssPosition = this.helper.css( "position" );
15421 //Generate the original position
15422 this.originalPosition = this._generatePosition( event );
15423 this.originalPageX = event.pageX;
15424 this.originalPageY = event.pageY;
15426 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
15427 ( o.cursorAt && this._adjustOffsetFromHelper( o.cursorAt ) );
15429 //Cache the former DOM position
15430 this.domPosition = {
15431 prev: this.currentItem.prev()[ 0 ],
15432 parent: this.currentItem.parent()[ 0 ]
15435 // If the helper is not the original, hide the original so it's not playing any role during
15436 // the drag, won't cause anything bad this way
15437 if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
15438 this.currentItem.hide();
15441 //Create the placeholder
15442 this._createPlaceholder();
15444 //Set a containment if given in the options
15445 if ( o.containment ) {
15446 this._setContainment();
15449 if ( o.cursor && o.cursor !== "auto" ) { // cursor option
15450 body = this.document.find( "body" );
15453 this.storedCursor = body.css( "cursor" );
15454 body.css( "cursor", o.cursor );
15456 this.storedStylesheet =
15457 $( "<style>*{ cursor: " + o.cursor + " !important; }</style>" ).appendTo( body );
15460 if ( o.opacity ) { // opacity option
15461 if ( this.helper.css( "opacity" ) ) {
15462 this._storedOpacity = this.helper.css( "opacity" );
15464 this.helper.css( "opacity", o.opacity );
15467 if ( o.zIndex ) { // zIndex option
15468 if ( this.helper.css( "zIndex" ) ) {
15469 this._storedZIndex = this.helper.css( "zIndex" );
15471 this.helper.css( "zIndex", o.zIndex );
15474 //Prepare scrolling
15475 if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
15476 this.scrollParent[ 0 ].tagName !== "HTML" ) {
15477 this.overflowOffset = this.scrollParent.offset();
15481 this._trigger( "start", event, this._uiHash() );
15483 //Recache the helper size
15484 if ( !this._preserveHelperProportions ) {
15485 this._cacheHelperProportions();
15488 //Post "activate" events to possible containers
15489 if ( !noActivation ) {
15490 for ( i = this.containers.length - 1; i >= 0; i-- ) {
15491 this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
15495 //Prepare possible droppables
15496 if ( $.ui.ddmanager ) {
15497 $.ui.ddmanager.current = this;
15500 if ( $.ui.ddmanager && !o.dropBehaviour ) {
15501 $.ui.ddmanager.prepareOffsets( this, event );
15504 this.dragging = true;
15506 this._addClass( this.helper, "ui-sortable-helper" );
15508 // Execute the drag once - this causes the helper not to be visiblebefore getting its
15509 // correct position
15510 this._mouseDrag( event );
15515 _mouseDrag: function( event ) {
15516 var i, item, itemElement, intersection,
15520 //Compute the helpers position
15521 this.position = this._generatePosition( event );
15522 this.positionAbs = this._convertPositionTo( "absolute" );
15524 if ( !this.lastPositionAbs ) {
15525 this.lastPositionAbs = this.positionAbs;
15529 if ( this.options.scroll ) {
15530 if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
15531 this.scrollParent[ 0 ].tagName !== "HTML" ) {
15533 if ( ( this.overflowOffset.top + this.scrollParent[ 0 ].offsetHeight ) -
15534 event.pageY < o.scrollSensitivity ) {
15535 this.scrollParent[ 0 ].scrollTop =
15536 scrolled = this.scrollParent[ 0 ].scrollTop + o.scrollSpeed;
15537 } else if ( event.pageY - this.overflowOffset.top < o.scrollSensitivity ) {
15538 this.scrollParent[ 0 ].scrollTop =
15539 scrolled = this.scrollParent[ 0 ].scrollTop - o.scrollSpeed;
15542 if ( ( this.overflowOffset.left + this.scrollParent[ 0 ].offsetWidth ) -
15543 event.pageX < o.scrollSensitivity ) {
15544 this.scrollParent[ 0 ].scrollLeft = scrolled =
15545 this.scrollParent[ 0 ].scrollLeft + o.scrollSpeed;
15546 } else if ( event.pageX - this.overflowOffset.left < o.scrollSensitivity ) {
15547 this.scrollParent[ 0 ].scrollLeft = scrolled =
15548 this.scrollParent[ 0 ].scrollLeft - o.scrollSpeed;
15553 if ( event.pageY - this.document.scrollTop() < o.scrollSensitivity ) {
15554 scrolled = this.document.scrollTop( this.document.scrollTop() - o.scrollSpeed );
15555 } else if ( this.window.height() - ( event.pageY - this.document.scrollTop() ) <
15556 o.scrollSensitivity ) {
15557 scrolled = this.document.scrollTop( this.document.scrollTop() + o.scrollSpeed );
15560 if ( event.pageX - this.document.scrollLeft() < o.scrollSensitivity ) {
15561 scrolled = this.document.scrollLeft(
15562 this.document.scrollLeft() - o.scrollSpeed
15564 } else if ( this.window.width() - ( event.pageX - this.document.scrollLeft() ) <
15565 o.scrollSensitivity ) {
15566 scrolled = this.document.scrollLeft(
15567 this.document.scrollLeft() + o.scrollSpeed
15573 if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) {
15574 $.ui.ddmanager.prepareOffsets( this, event );
15578 //Regenerate the absolute position used for position checks
15579 this.positionAbs = this._convertPositionTo( "absolute" );
15581 //Set the helper position
15582 if ( !this.options.axis || this.options.axis !== "y" ) {
15583 this.helper[ 0 ].style.left = this.position.left + "px";
15585 if ( !this.options.axis || this.options.axis !== "x" ) {
15586 this.helper[ 0 ].style.top = this.position.top + "px";
15590 for ( i = this.items.length - 1; i >= 0; i-- ) {
15592 //Cache variables and intersection, continue if no intersection
15593 item = this.items[ i ];
15594 itemElement = item.item[ 0 ];
15595 intersection = this._intersectsWithPointer( item );
15596 if ( !intersection ) {
15600 // Only put the placeholder inside the current Container, skip all
15601 // items from other containers. This works because when moving
15602 // an item from one container to another the
15603 // currentContainer is switched before the placeholder is moved.
15605 // Without this, moving items in "sub-sortables" can cause
15606 // the placeholder to jitter between the outer and inner container.
15607 if ( item.instance !== this.currentContainer ) {
15611 // Cannot intersect with itself
15612 // no useless actions that have been done before
15613 // no action if the item moved is the parent of the item checked
15614 if ( itemElement !== this.currentItem[ 0 ] &&
15615 this.placeholder[ intersection === 1 ? "next" : "prev" ]()[ 0 ] !== itemElement &&
15616 !$.contains( this.placeholder[ 0 ], itemElement ) &&
15617 ( this.options.type === "semi-dynamic" ?
15618 !$.contains( this.element[ 0 ], itemElement ) :
15623 this.direction = intersection === 1 ? "down" : "up";
15625 if ( this.options.tolerance === "pointer" || this._intersectsWithSides( item ) ) {
15626 this._rearrange( event, item );
15631 this._trigger( "change", event, this._uiHash() );
15636 //Post events to containers
15637 this._contactContainers( event );
15639 //Interconnect with droppables
15640 if ( $.ui.ddmanager ) {
15641 $.ui.ddmanager.drag( this, event );
15645 this._trigger( "sort", event, this._uiHash() );
15647 this.lastPositionAbs = this.positionAbs;
15652 _mouseStop: function( event, noPropagation ) {
15658 //If we are using droppables, inform the manager about the drop
15659 if ( $.ui.ddmanager && !this.options.dropBehaviour ) {
15660 $.ui.ddmanager.drop( this, event );
15663 if ( this.options.revert ) {
15665 cur = this.placeholder.offset(),
15666 axis = this.options.axis,
15669 if ( !axis || axis === "x" ) {
15670 animation.left = cur.left - this.offset.parent.left - this.margins.left +
15671 ( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
15673 this.offsetParent[ 0 ].scrollLeft
15676 if ( !axis || axis === "y" ) {
15677 animation.top = cur.top - this.offset.parent.top - this.margins.top +
15678 ( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
15680 this.offsetParent[ 0 ].scrollTop
15683 this.reverting = true;
15684 $( this.helper ).animate(
15686 parseInt( this.options.revert, 10 ) || 500,
15688 that._clear( event );
15692 this._clear( event, noPropagation );
15699 cancel: function() {
15701 if ( this.dragging ) {
15703 this._mouseUp( new $.Event( "mouseup", { target: null } ) );
15705 if ( this.options.helper === "original" ) {
15706 this.currentItem.css( this._storedCSS );
15707 this._removeClass( this.currentItem, "ui-sortable-helper" );
15709 this.currentItem.show();
15712 //Post deactivating events to containers
15713 for ( var i = this.containers.length - 1; i >= 0; i-- ) {
15714 this.containers[ i ]._trigger( "deactivate", null, this._uiHash( this ) );
15715 if ( this.containers[ i ].containerCache.over ) {
15716 this.containers[ i ]._trigger( "out", null, this._uiHash( this ) );
15717 this.containers[ i ].containerCache.over = 0;
15723 if ( this.placeholder ) {
15725 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
15726 // it unbinds ALL events from the original node!
15727 if ( this.placeholder[ 0 ].parentNode ) {
15728 this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );
15730 if ( this.options.helper !== "original" && this.helper &&
15731 this.helper[ 0 ].parentNode ) {
15732 this.helper.remove();
15742 if ( this.domPosition.prev ) {
15743 $( this.domPosition.prev ).after( this.currentItem );
15745 $( this.domPosition.parent ).prepend( this.currentItem );
15753 serialize: function( o ) {
15755 var items = this._getItemsAsjQuery( o && o.connected ),
15759 $( items ).each( function() {
15760 var res = ( $( o.item || this ).attr( o.attribute || "id" ) || "" )
15761 .match( o.expression || ( /(.+)[\-=_](.+)/ ) );
15764 ( o.key || res[ 1 ] + "[]" ) +
15765 "=" + ( o.key && o.expression ? res[ 1 ] : res[ 2 ] ) );
15769 if ( !str.length && o.key ) {
15770 str.push( o.key + "=" );
15773 return str.join( "&" );
15777 toArray: function( o ) {
15779 var items = this._getItemsAsjQuery( o && o.connected ),
15784 items.each( function() {
15785 ret.push( $( o.item || this ).attr( o.attribute || "id" ) || "" );
15791 /* Be careful with the following core functions */
15792 _intersectsWith: function( item ) {
15794 var x1 = this.positionAbs.left,
15795 x2 = x1 + this.helperProportions.width,
15796 y1 = this.positionAbs.top,
15797 y2 = y1 + this.helperProportions.height,
15799 r = l + item.width,
15801 b = t + item.height,
15802 dyClick = this.offset.click.top,
15803 dxClick = this.offset.click.left,
15804 isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t &&
15805 ( y1 + dyClick ) < b ),
15806 isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l &&
15807 ( x1 + dxClick ) < r ),
15808 isOverElement = isOverElementHeight && isOverElementWidth;
15810 if ( this.options.tolerance === "pointer" ||
15811 this.options.forcePointerForContainers ||
15812 ( this.options.tolerance !== "pointer" &&
15813 this.helperProportions[ this.floating ? "width" : "height" ] >
15814 item[ this.floating ? "width" : "height" ] )
15816 return isOverElement;
15819 return ( l < x1 + ( this.helperProportions.width / 2 ) && // Right Half
15820 x2 - ( this.helperProportions.width / 2 ) < r && // Left Half
15821 t < y1 + ( this.helperProportions.height / 2 ) && // Bottom Half
15822 y2 - ( this.helperProportions.height / 2 ) < b ); // Top Half
15827 _intersectsWithPointer: function( item ) {
15828 var verticalDirection, horizontalDirection,
15829 isOverElementHeight = ( this.options.axis === "x" ) ||
15831 this.positionAbs.top + this.offset.click.top, item.top, item.height ),
15832 isOverElementWidth = ( this.options.axis === "y" ) ||
15834 this.positionAbs.left + this.offset.click.left, item.left, item.width ),
15835 isOverElement = isOverElementHeight && isOverElementWidth;
15837 if ( !isOverElement ) {
15841 verticalDirection = this._getDragVerticalDirection();
15842 horizontalDirection = this._getDragHorizontalDirection();
15844 return this.floating ?
15845 ( ( horizontalDirection === "right" || verticalDirection === "down" ) ? 2 : 1 )
15846 : ( verticalDirection && ( verticalDirection === "down" ? 2 : 1 ) );
15850 _intersectsWithSides: function( item ) {
15852 var isOverBottomHalf = this._isOverAxis( this.positionAbs.top +
15853 this.offset.click.top, item.top + ( item.height / 2 ), item.height ),
15854 isOverRightHalf = this._isOverAxis( this.positionAbs.left +
15855 this.offset.click.left, item.left + ( item.width / 2 ), item.width ),
15856 verticalDirection = this._getDragVerticalDirection(),
15857 horizontalDirection = this._getDragHorizontalDirection();
15859 if ( this.floating && horizontalDirection ) {
15860 return ( ( horizontalDirection === "right" && isOverRightHalf ) ||
15861 ( horizontalDirection === "left" && !isOverRightHalf ) );
15863 return verticalDirection && ( ( verticalDirection === "down" && isOverBottomHalf ) ||
15864 ( verticalDirection === "up" && !isOverBottomHalf ) );
15869 _getDragVerticalDirection: function() {
15870 var delta = this.positionAbs.top - this.lastPositionAbs.top;
15871 return delta !== 0 && ( delta > 0 ? "down" : "up" );
15874 _getDragHorizontalDirection: function() {
15875 var delta = this.positionAbs.left - this.lastPositionAbs.left;
15876 return delta !== 0 && ( delta > 0 ? "right" : "left" );
15879 refresh: function( event ) {
15880 this._refreshItems( event );
15881 this._setHandleClassName();
15882 this.refreshPositions();
15886 _connectWith: function() {
15887 var options = this.options;
15888 return options.connectWith.constructor === String ?
15889 [ options.connectWith ] :
15890 options.connectWith;
15893 _getItemsAsjQuery: function( connected ) {
15895 var i, j, cur, inst,
15898 connectWith = this._connectWith();
15900 if ( connectWith && connected ) {
15901 for ( i = connectWith.length - 1; i >= 0; i-- ) {
15902 cur = $( connectWith[ i ], this.document[ 0 ] );
15903 for ( j = cur.length - 1; j >= 0; j-- ) {
15904 inst = $.data( cur[ j ], this.widgetFullName );
15905 if ( inst && inst !== this && !inst.options.disabled ) {
15906 queries.push( [ $.isFunction( inst.options.items ) ?
15907 inst.options.items.call( inst.element ) :
15908 $( inst.options.items, inst.element )
15909 .not( ".ui-sortable-helper" )
15910 .not( ".ui-sortable-placeholder" ), inst ] );
15916 queries.push( [ $.isFunction( this.options.items ) ?
15918 .call( this.element, null, { options: this.options, item: this.currentItem } ) :
15919 $( this.options.items, this.element )
15920 .not( ".ui-sortable-helper" )
15921 .not( ".ui-sortable-placeholder" ), this ] );
15923 function addItems() {
15924 items.push( this );
15926 for ( i = queries.length - 1; i >= 0; i-- ) {
15927 queries[ i ][ 0 ].each( addItems );
15934 _removeCurrentsFromItems: function() {
15936 var list = this.currentItem.find( ":data(" + this.widgetName + "-item)" );
15938 this.items = $.grep( this.items, function( item ) {
15939 for ( var j = 0; j < list.length; j++ ) {
15940 if ( list[ j ] === item.item[ 0 ] ) {
15949 _refreshItems: function( event ) {
15952 this.containers = [ this ];
15954 var i, j, cur, inst, targetData, _queries, item, queriesLength,
15955 items = this.items,
15956 queries = [ [ $.isFunction( this.options.items ) ?
15957 this.options.items.call( this.element[ 0 ], event, { item: this.currentItem } ) :
15958 $( this.options.items, this.element ), this ] ],
15959 connectWith = this._connectWith();
15961 //Shouldn't be run the first time through due to massive slow-down
15962 if ( connectWith && this.ready ) {
15963 for ( i = connectWith.length - 1; i >= 0; i-- ) {
15964 cur = $( connectWith[ i ], this.document[ 0 ] );
15965 for ( j = cur.length - 1; j >= 0; j-- ) {
15966 inst = $.data( cur[ j ], this.widgetFullName );
15967 if ( inst && inst !== this && !inst.options.disabled ) {
15968 queries.push( [ $.isFunction( inst.options.items ) ?
15970 .call( inst.element[ 0 ], event, { item: this.currentItem } ) :
15971 $( inst.options.items, inst.element ), inst ] );
15972 this.containers.push( inst );
15978 for ( i = queries.length - 1; i >= 0; i-- ) {
15979 targetData = queries[ i ][ 1 ];
15980 _queries = queries[ i ][ 0 ];
15982 for ( j = 0, queriesLength = _queries.length; j < queriesLength; j++ ) {
15983 item = $( _queries[ j ] );
15985 // Data for target checking (mouse manager)
15986 item.data( this.widgetName + "-item", targetData );
15990 instance: targetData,
15991 width: 0, height: 0,
15999 refreshPositions: function( fast ) {
16001 // Determine whether items are being displayed horizontally
16002 this.floating = this.items.length ?
16003 this.options.axis === "x" || this._isFloating( this.items[ 0 ].item ) :
16006 //This has to be redone because due to the item being moved out/into the offsetParent,
16007 // the offsetParent's position will change
16008 if ( this.offsetParent && this.helper ) {
16009 this.offset.parent = this._getParentOffset();
16014 for ( i = this.items.length - 1; i >= 0; i-- ) {
16015 item = this.items[ i ];
16017 //We ignore calculating positions of all connected containers when we're not over them
16018 if ( item.instance !== this.currentContainer && this.currentContainer &&
16019 item.item[ 0 ] !== this.currentItem[ 0 ] ) {
16023 t = this.options.toleranceElement ?
16024 $( this.options.toleranceElement, item.item ) :
16028 item.width = t.outerWidth();
16029 item.height = t.outerHeight();
16033 item.left = p.left;
16037 if ( this.options.custom && this.options.custom.refreshContainers ) {
16038 this.options.custom.refreshContainers.call( this );
16040 for ( i = this.containers.length - 1; i >= 0; i-- ) {
16041 p = this.containers[ i ].element.offset();
16042 this.containers[ i ].containerCache.left = p.left;
16043 this.containers[ i ].containerCache.top = p.top;
16044 this.containers[ i ].containerCache.width =
16045 this.containers[ i ].element.outerWidth();
16046 this.containers[ i ].containerCache.height =
16047 this.containers[ i ].element.outerHeight();
16054 _createPlaceholder: function( that ) {
16055 that = that || this;
16059 if ( !o.placeholder || o.placeholder.constructor === String ) {
16060 className = o.placeholder;
16062 element: function() {
16064 var nodeName = that.currentItem[ 0 ].nodeName.toLowerCase(),
16065 element = $( "<" + nodeName + ">", that.document[ 0 ] );
16067 that._addClass( element, "ui-sortable-placeholder",
16068 className || that.currentItem[ 0 ].className )
16069 ._removeClass( element, "ui-sortable-helper" );
16071 if ( nodeName === "tbody" ) {
16072 that._createTrPlaceholder(
16073 that.currentItem.find( "tr" ).eq( 0 ),
16074 $( "<tr>", that.document[ 0 ] ).appendTo( element )
16076 } else if ( nodeName === "tr" ) {
16077 that._createTrPlaceholder( that.currentItem, element );
16078 } else if ( nodeName === "img" ) {
16079 element.attr( "src", that.currentItem.attr( "src" ) );
16082 if ( !className ) {
16083 element.css( "visibility", "hidden" );
16088 update: function( container, p ) {
16090 // 1. If a className is set as 'placeholder option, we don't force sizes -
16091 // the class is responsible for that
16092 // 2. The option 'forcePlaceholderSize can be enabled to force it even if a
16093 // class name is specified
16094 if ( className && !o.forcePlaceholderSize ) {
16098 //If the element doesn't have a actual height by itself (without styles coming
16099 // from a stylesheet), it receives the inline height from the dragged item
16100 if ( !p.height() ) {
16102 that.currentItem.innerHeight() -
16103 parseInt( that.currentItem.css( "paddingTop" ) || 0, 10 ) -
16104 parseInt( that.currentItem.css( "paddingBottom" ) || 0, 10 ) );
16106 if ( !p.width() ) {
16108 that.currentItem.innerWidth() -
16109 parseInt( that.currentItem.css( "paddingLeft" ) || 0, 10 ) -
16110 parseInt( that.currentItem.css( "paddingRight" ) || 0, 10 ) );
16116 //Create the placeholder
16117 that.placeholder = $( o.placeholder.element.call( that.element, that.currentItem ) );
16119 //Append it after the actual current item
16120 that.currentItem.after( that.placeholder );
16122 //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
16123 o.placeholder.update( that, that.placeholder );
16127 _createTrPlaceholder: function( sourceTr, targetTr ) {
16130 sourceTr.children().each( function() {
16131 $( "<td> </td>", that.document[ 0 ] )
16132 .attr( "colspan", $( this ).attr( "colspan" ) || 1 )
16133 .appendTo( targetTr );
16137 _contactContainers: function( event ) {
16138 var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom,
16140 innermostContainer = null,
16141 innermostIndex = null;
16143 // Get innermost container that intersects with item
16144 for ( i = this.containers.length - 1; i >= 0; i-- ) {
16146 // Never consider a container that's located within the item itself
16147 if ( $.contains( this.currentItem[ 0 ], this.containers[ i ].element[ 0 ] ) ) {
16151 if ( this._intersectsWith( this.containers[ i ].containerCache ) ) {
16153 // If we've already found a container and it's more "inner" than this, then continue
16154 if ( innermostContainer &&
16156 this.containers[ i ].element[ 0 ],
16157 innermostContainer.element[ 0 ] ) ) {
16161 innermostContainer = this.containers[ i ];
16162 innermostIndex = i;
16166 // container doesn't intersect. trigger "out" event if necessary
16167 if ( this.containers[ i ].containerCache.over ) {
16168 this.containers[ i ]._trigger( "out", event, this._uiHash( this ) );
16169 this.containers[ i ].containerCache.over = 0;
16175 // If no intersecting containers found, return
16176 if ( !innermostContainer ) {
16180 // Move the item into the container if it's not there already
16181 if ( this.containers.length === 1 ) {
16182 if ( !this.containers[ innermostIndex ].containerCache.over ) {
16183 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
16184 this.containers[ innermostIndex ].containerCache.over = 1;
16188 // When entering a new container, we will find the item with the least distance and
16189 // append our item near it
16191 itemWithLeastDistance = null;
16192 floating = innermostContainer.floating || this._isFloating( this.currentItem );
16193 posProperty = floating ? "left" : "top";
16194 sizeProperty = floating ? "width" : "height";
16195 axis = floating ? "pageX" : "pageY";
16197 for ( j = this.items.length - 1; j >= 0; j-- ) {
16199 this.containers[ innermostIndex ].element[ 0 ], this.items[ j ].item[ 0 ] )
16203 if ( this.items[ j ].item[ 0 ] === this.currentItem[ 0 ] ) {
16207 cur = this.items[ j ].item.offset()[ posProperty ];
16208 nearBottom = false;
16209 if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) {
16213 if ( Math.abs( event[ axis ] - cur ) < dist ) {
16214 dist = Math.abs( event[ axis ] - cur );
16215 itemWithLeastDistance = this.items[ j ];
16216 this.direction = nearBottom ? "up" : "down";
16220 //Check if dropOnEmpty is enabled
16221 if ( !itemWithLeastDistance && !this.options.dropOnEmpty ) {
16225 if ( this.currentContainer === this.containers[ innermostIndex ] ) {
16226 if ( !this.currentContainer.containerCache.over ) {
16227 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() );
16228 this.currentContainer.containerCache.over = 1;
16233 itemWithLeastDistance ?
16234 this._rearrange( event, itemWithLeastDistance, null, true ) :
16235 this._rearrange( event, null, this.containers[ innermostIndex ].element, true );
16236 this._trigger( "change", event, this._uiHash() );
16237 this.containers[ innermostIndex ]._trigger( "change", event, this._uiHash( this ) );
16238 this.currentContainer = this.containers[ innermostIndex ];
16240 //Update the placeholder
16241 this.options.placeholder.update( this.currentContainer, this.placeholder );
16243 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
16244 this.containers[ innermostIndex ].containerCache.over = 1;
16249 _createHelper: function( event ) {
16251 var o = this.options,
16252 helper = $.isFunction( o.helper ) ?
16253 $( o.helper.apply( this.element[ 0 ], [ event, this.currentItem ] ) ) :
16254 ( o.helper === "clone" ? this.currentItem.clone() : this.currentItem );
16256 //Add the helper to the DOM if that didn't happen already
16257 if ( !helper.parents( "body" ).length ) {
16258 $( o.appendTo !== "parent" ?
16260 this.currentItem[ 0 ].parentNode )[ 0 ].appendChild( helper[ 0 ] );
16263 if ( helper[ 0 ] === this.currentItem[ 0 ] ) {
16264 this._storedCSS = {
16265 width: this.currentItem[ 0 ].style.width,
16266 height: this.currentItem[ 0 ].style.height,
16267 position: this.currentItem.css( "position" ),
16268 top: this.currentItem.css( "top" ),
16269 left: this.currentItem.css( "left" )
16273 if ( !helper[ 0 ].style.width || o.forceHelperSize ) {
16274 helper.width( this.currentItem.width() );
16276 if ( !helper[ 0 ].style.height || o.forceHelperSize ) {
16277 helper.height( this.currentItem.height() );
16284 _adjustOffsetFromHelper: function( obj ) {
16285 if ( typeof obj === "string" ) {
16286 obj = obj.split( " " );
16288 if ( $.isArray( obj ) ) {
16289 obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 };
16291 if ( "left" in obj ) {
16292 this.offset.click.left = obj.left + this.margins.left;
16294 if ( "right" in obj ) {
16295 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
16297 if ( "top" in obj ) {
16298 this.offset.click.top = obj.top + this.margins.top;
16300 if ( "bottom" in obj ) {
16301 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
16305 _getParentOffset: function() {
16307 //Get the offsetParent and cache its position
16308 this.offsetParent = this.helper.offsetParent();
16309 var po = this.offsetParent.offset();
16311 // This is a special case where we need to modify a offset calculated on start, since the
16312 // following happened:
16313 // 1. The position of the helper is absolute, so it's position is calculated based on the
16314 // next positioned parent
16315 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't
16316 // the document, which means that the scroll is included in the initial calculation of the
16317 // offset of the parent, and never recalculated upon drag
16318 if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== this.document[ 0 ] &&
16319 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) {
16320 po.left += this.scrollParent.scrollLeft();
16321 po.top += this.scrollParent.scrollTop();
16324 // This needs to be actually done for all browsers, since pageX/pageY includes this
16325 // information with an ugly IE fix
16326 if ( this.offsetParent[ 0 ] === this.document[ 0 ].body ||
16327 ( this.offsetParent[ 0 ].tagName &&
16328 this.offsetParent[ 0 ].tagName.toLowerCase() === "html" && $.ui.ie ) ) {
16329 po = { top: 0, left: 0 };
16333 top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ),
16334 left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 )
16339 _getRelativeOffset: function() {
16341 if ( this.cssPosition === "relative" ) {
16342 var p = this.currentItem.position();
16344 top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) +
16345 this.scrollParent.scrollTop(),
16346 left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) +
16347 this.scrollParent.scrollLeft()
16350 return { top: 0, left: 0 };
16355 _cacheMargins: function() {
16357 left: ( parseInt( this.currentItem.css( "marginLeft" ), 10 ) || 0 ),
16358 top: ( parseInt( this.currentItem.css( "marginTop" ), 10 ) || 0 )
16362 _cacheHelperProportions: function() {
16363 this.helperProportions = {
16364 width: this.helper.outerWidth(),
16365 height: this.helper.outerHeight()
16369 _setContainment: function() {
16373 if ( o.containment === "parent" ) {
16374 o.containment = this.helper[ 0 ].parentNode;
16376 if ( o.containment === "document" || o.containment === "window" ) {
16377 this.containment = [
16378 0 - this.offset.relative.left - this.offset.parent.left,
16379 0 - this.offset.relative.top - this.offset.parent.top,
16380 o.containment === "document" ?
16381 this.document.width() :
16382 this.window.width() - this.helperProportions.width - this.margins.left,
16383 ( o.containment === "document" ?
16384 ( this.document.height() || document.body.parentNode.scrollHeight ) :
16385 this.window.height() || this.document[ 0 ].body.parentNode.scrollHeight
16386 ) - this.helperProportions.height - this.margins.top
16390 if ( !( /^(document|window|parent)$/ ).test( o.containment ) ) {
16391 ce = $( o.containment )[ 0 ];
16392 co = $( o.containment ).offset();
16393 over = ( $( ce ).css( "overflow" ) !== "hidden" );
16395 this.containment = [
16396 co.left + ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) +
16397 ( parseInt( $( ce ).css( "paddingLeft" ), 10 ) || 0 ) - this.margins.left,
16398 co.top + ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) +
16399 ( parseInt( $( ce ).css( "paddingTop" ), 10 ) || 0 ) - this.margins.top,
16400 co.left + ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
16401 ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) -
16402 ( parseInt( $( ce ).css( "paddingRight" ), 10 ) || 0 ) -
16403 this.helperProportions.width - this.margins.left,
16404 co.top + ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
16405 ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) -
16406 ( parseInt( $( ce ).css( "paddingBottom" ), 10 ) || 0 ) -
16407 this.helperProportions.height - this.margins.top
16413 _convertPositionTo: function( d, pos ) {
16416 pos = this.position;
16418 var mod = d === "absolute" ? 1 : -1,
16419 scroll = this.cssPosition === "absolute" &&
16420 !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
16421 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
16422 this.offsetParent :
16424 scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );
16429 // The absolute mouse position
16432 // Only for relative positioned nodes: Relative offset from element to offset parent
16433 this.offset.relative.top * mod +
16435 // The offsetParent's offset without borders (offset + border)
16436 this.offset.parent.top * mod -
16437 ( ( this.cssPosition === "fixed" ?
16438 -this.scrollParent.scrollTop() :
16439 ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod )
16443 // The absolute mouse position
16446 // Only for relative positioned nodes: Relative offset from element to offset parent
16447 this.offset.relative.left * mod +
16449 // The offsetParent's offset without borders (offset + border)
16450 this.offset.parent.left * mod -
16451 ( ( this.cssPosition === "fixed" ?
16452 -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 :
16453 scroll.scrollLeft() ) * mod )
16459 _generatePosition: function( event ) {
16463 pageX = event.pageX,
16464 pageY = event.pageY,
16465 scroll = this.cssPosition === "absolute" &&
16466 !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
16467 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
16468 this.offsetParent :
16470 scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );
16472 // This is another very weird special case that only happens for relative elements:
16473 // 1. If the css position is relative
16474 // 2. and the scroll parent is the document or similar to the offset parent
16475 // we have to refresh the relative offset during the scroll so there are no jumps
16476 if ( this.cssPosition === "relative" && !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
16477 this.scrollParent[ 0 ] !== this.offsetParent[ 0 ] ) ) {
16478 this.offset.relative = this._getRelativeOffset();
16482 * - Position constraining -
16483 * Constrain the position to a mix of grid, containment.
16486 if ( this.originalPosition ) { //If we are not dragging yet, we won't check for options
16488 if ( this.containment ) {
16489 if ( event.pageX - this.offset.click.left < this.containment[ 0 ] ) {
16490 pageX = this.containment[ 0 ] + this.offset.click.left;
16492 if ( event.pageY - this.offset.click.top < this.containment[ 1 ] ) {
16493 pageY = this.containment[ 1 ] + this.offset.click.top;
16495 if ( event.pageX - this.offset.click.left > this.containment[ 2 ] ) {
16496 pageX = this.containment[ 2 ] + this.offset.click.left;
16498 if ( event.pageY - this.offset.click.top > this.containment[ 3 ] ) {
16499 pageY = this.containment[ 3 ] + this.offset.click.top;
16504 top = this.originalPageY + Math.round( ( pageY - this.originalPageY ) /
16505 o.grid[ 1 ] ) * o.grid[ 1 ];
16506 pageY = this.containment ?
16507 ( ( top - this.offset.click.top >= this.containment[ 1 ] &&
16508 top - this.offset.click.top <= this.containment[ 3 ] ) ?
16510 ( ( top - this.offset.click.top >= this.containment[ 1 ] ) ?
16511 top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) :
16514 left = this.originalPageX + Math.round( ( pageX - this.originalPageX ) /
16515 o.grid[ 0 ] ) * o.grid[ 0 ];
16516 pageX = this.containment ?
16517 ( ( left - this.offset.click.left >= this.containment[ 0 ] &&
16518 left - this.offset.click.left <= this.containment[ 2 ] ) ?
16520 ( ( left - this.offset.click.left >= this.containment[ 0 ] ) ?
16521 left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) :
16530 // The absolute mouse position
16533 // Click offset (relative to the element)
16534 this.offset.click.top -
16536 // Only for relative positioned nodes: Relative offset from element to offset parent
16537 this.offset.relative.top -
16539 // The offsetParent's offset without borders (offset + border)
16540 this.offset.parent.top +
16541 ( ( this.cssPosition === "fixed" ?
16542 -this.scrollParent.scrollTop() :
16543 ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) )
16547 // The absolute mouse position
16550 // Click offset (relative to the element)
16551 this.offset.click.left -
16553 // Only for relative positioned nodes: Relative offset from element to offset parent
16554 this.offset.relative.left -
16556 // The offsetParent's offset without borders (offset + border)
16557 this.offset.parent.left +
16558 ( ( this.cssPosition === "fixed" ?
16559 -this.scrollParent.scrollLeft() :
16560 scrollIsRootNode ? 0 : scroll.scrollLeft() ) )
16566 _rearrange: function( event, i, a, hardRefresh ) {
16568 a ? a[ 0 ].appendChild( this.placeholder[ 0 ] ) :
16569 i.item[ 0 ].parentNode.insertBefore( this.placeholder[ 0 ],
16570 ( this.direction === "down" ? i.item[ 0 ] : i.item[ 0 ].nextSibling ) );
16572 //Various things done here to improve the performance:
16573 // 1. we create a setTimeout, that calls refreshPositions
16574 // 2. on the instance, we have a counter variable, that get's higher after every append
16575 // 3. on the local scope, we copy the counter variable, and check in the timeout,
16576 // if it's still the same
16577 // 4. this lets only the last addition to the timeout stack through
16578 this.counter = this.counter ? ++this.counter : 1;
16579 var counter = this.counter;
16581 this._delay( function() {
16582 if ( counter === this.counter ) {
16584 //Precompute after each DOM insertion, NOT on mousemove
16585 this.refreshPositions( !hardRefresh );
16591 _clear: function( event, noPropagation ) {
16593 this.reverting = false;
16595 // We delay all events that have to be triggered to after the point where the placeholder
16596 // has been removed and everything else normalized again
16598 delayedTriggers = [];
16600 // We first have to update the dom position of the actual currentItem
16601 // Note: don't do it if the current item is already removed (by a user), or it gets
16602 // reappended (see #4088)
16603 if ( !this._noFinalSort && this.currentItem.parent().length ) {
16604 this.placeholder.before( this.currentItem );
16606 this._noFinalSort = null;
16608 if ( this.helper[ 0 ] === this.currentItem[ 0 ] ) {
16609 for ( i in this._storedCSS ) {
16610 if ( this._storedCSS[ i ] === "auto" || this._storedCSS[ i ] === "static" ) {
16611 this._storedCSS[ i ] = "";
16614 this.currentItem.css( this._storedCSS );
16615 this._removeClass( this.currentItem, "ui-sortable-helper" );
16617 this.currentItem.show();
16620 if ( this.fromOutside && !noPropagation ) {
16621 delayedTriggers.push( function( event ) {
16622 this._trigger( "receive", event, this._uiHash( this.fromOutside ) );
16625 if ( ( this.fromOutside ||
16626 this.domPosition.prev !==
16627 this.currentItem.prev().not( ".ui-sortable-helper" )[ 0 ] ||
16628 this.domPosition.parent !== this.currentItem.parent()[ 0 ] ) && !noPropagation ) {
16630 // Trigger update callback if the DOM position has changed
16631 delayedTriggers.push( function( event ) {
16632 this._trigger( "update", event, this._uiHash() );
16636 // Check if the items Container has Changed and trigger appropriate
16638 if ( this !== this.currentContainer ) {
16639 if ( !noPropagation ) {
16640 delayedTriggers.push( function( event ) {
16641 this._trigger( "remove", event, this._uiHash() );
16643 delayedTriggers.push( ( function( c ) {
16644 return function( event ) {
16645 c._trigger( "receive", event, this._uiHash( this ) );
16647 } ).call( this, this.currentContainer ) );
16648 delayedTriggers.push( ( function( c ) {
16649 return function( event ) {
16650 c._trigger( "update", event, this._uiHash( this ) );
16652 } ).call( this, this.currentContainer ) );
16656 //Post events to containers
16657 function delayEvent( type, instance, container ) {
16658 return function( event ) {
16659 container._trigger( type, event, instance._uiHash( instance ) );
16662 for ( i = this.containers.length - 1; i >= 0; i-- ) {
16663 if ( !noPropagation ) {
16664 delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) );
16666 if ( this.containers[ i ].containerCache.over ) {
16667 delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) );
16668 this.containers[ i ].containerCache.over = 0;
16672 //Do what was originally in plugins
16673 if ( this.storedCursor ) {
16674 this.document.find( "body" ).css( "cursor", this.storedCursor );
16675 this.storedStylesheet.remove();
16677 if ( this._storedOpacity ) {
16678 this.helper.css( "opacity", this._storedOpacity );
16680 if ( this._storedZIndex ) {
16681 this.helper.css( "zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex );
16684 this.dragging = false;
16686 if ( !noPropagation ) {
16687 this._trigger( "beforeStop", event, this._uiHash() );
16690 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
16691 // it unbinds ALL events from the original node!
16692 this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );
16694 if ( !this.cancelHelperRemoval ) {
16695 if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
16696 this.helper.remove();
16698 this.helper = null;
16701 if ( !noPropagation ) {
16702 for ( i = 0; i < delayedTriggers.length; i++ ) {
16704 // Trigger all delayed events
16705 delayedTriggers[ i ].call( this, event );
16707 this._trigger( "stop", event, this._uiHash() );
16710 this.fromOutside = false;
16711 return !this.cancelHelperRemoval;
16715 _trigger: function() {
16716 if ( $.Widget.prototype._trigger.apply( this, arguments ) === false ) {
16721 _uiHash: function( _inst ) {
16722 var inst = _inst || this;
16724 helper: inst.helper,
16725 placeholder: inst.placeholder || $( [] ),
16726 position: inst.position,
16727 originalPosition: inst.originalPosition,
16728 offset: inst.positionAbs,
16729 item: inst.currentItem,
16730 sender: _inst ? _inst.element : null
16738 * jQuery UI Spinner 1.12.1
16739 * http://jqueryui.com
16741 * Copyright jQuery Foundation and other contributors
16742 * Released under the MIT license.
16743 * http://jquery.org/license
16748 //>>description: Displays buttons to easily input numbers via the keyboard or mouse.
16749 //>>docs: http://api.jqueryui.com/spinner/
16750 //>>demos: http://jqueryui.com/spinner/
16751 //>>css.structure: ../../themes/base/core.css
16752 //>>css.structure: ../../themes/base/spinner.css
16753 //>>css.theme: ../../themes/base/theme.css
16757 function spinnerModifer( fn ) {
16758 return function() {
16759 var previous = this.element.val();
16760 fn.apply( this, arguments );
16762 if ( previous !== this.element.val() ) {
16763 this._trigger( "change" );
16768 $.widget( "ui.spinner", {
16770 defaultElement: "<input>",
16771 widgetEventPrefix: "spin",
16774 "ui-spinner": "ui-corner-all",
16775 "ui-spinner-down": "ui-corner-br",
16776 "ui-spinner-up": "ui-corner-tr"
16780 down: "ui-icon-triangle-1-s",
16781 up: "ui-icon-triangle-1-n"
16786 numberFormat: null,
16796 _create: function() {
16798 // handle string values that need to be parsed
16799 this._setOption( "max", this.options.max );
16800 this._setOption( "min", this.options.min );
16801 this._setOption( "step", this.options.step );
16803 // Only format if there is a value, prevents the field from being marked
16804 // as invalid in Firefox, see #9573.
16805 if ( this.value() !== "" ) {
16807 // Format the value, but don't constrain.
16808 this._value( this.element.val(), true );
16812 this._on( this._events );
16815 // Turning off autocomplete prevents the browser from remembering the
16816 // value when navigating through history, so we re-enable autocomplete
16817 // if the page is unloaded before the widget is destroyed. #7790
16818 this._on( this.window, {
16819 beforeunload: function() {
16820 this.element.removeAttr( "autocomplete" );
16825 _getCreateOptions: function() {
16826 var options = this._super();
16827 var element = this.element;
16829 $.each( [ "min", "max", "step" ], function( i, option ) {
16830 var value = element.attr( option );
16831 if ( value != null && value.length ) {
16832 options[ option ] = value;
16840 keydown: function( event ) {
16841 if ( this._start( event ) && this._keydown( event ) ) {
16842 event.preventDefault();
16846 focus: function() {
16847 this.previous = this.element.val();
16849 blur: function( event ) {
16850 if ( this.cancelBlur ) {
16851 delete this.cancelBlur;
16857 if ( this.previous !== this.element.val() ) {
16858 this._trigger( "change", event );
16861 mousewheel: function( event, delta ) {
16865 if ( !this.spinning && !this._start( event ) ) {
16869 this._spin( ( delta > 0 ? 1 : -1 ) * this.options.step, event );
16870 clearTimeout( this.mousewheelTimer );
16871 this.mousewheelTimer = this._delay( function() {
16872 if ( this.spinning ) {
16873 this._stop( event );
16876 event.preventDefault();
16878 "mousedown .ui-spinner-button": function( event ) {
16881 // We never want the buttons to have focus; whenever the user is
16882 // interacting with the spinner, the focus should be on the input.
16883 // If the input is focused then this.previous is properly set from
16884 // when the input first received focus. If the input is not focused
16885 // then we need to set this.previous based on the value before spinning.
16886 previous = this.element[ 0 ] === $.ui.safeActiveElement( this.document[ 0 ] ) ?
16887 this.previous : this.element.val();
16888 function checkFocus() {
16889 var isActive = this.element[ 0 ] === $.ui.safeActiveElement( this.document[ 0 ] );
16891 this.element.trigger( "focus" );
16892 this.previous = previous;
16895 // IE sets focus asynchronously, so we need to check if focus
16896 // moved off of the input because the user clicked on the button.
16897 this._delay( function() {
16898 this.previous = previous;
16903 // Ensure focus is on (or stays on) the text field
16904 event.preventDefault();
16905 checkFocus.call( this );
16908 // IE doesn't prevent moving focus even with event.preventDefault()
16909 // so we set a flag to know when we should ignore the blur event
16910 // and check (again) if focus moved off of the input.
16911 this.cancelBlur = true;
16912 this._delay( function() {
16913 delete this.cancelBlur;
16914 checkFocus.call( this );
16917 if ( this._start( event ) === false ) {
16921 this._repeat( null, $( event.currentTarget )
16922 .hasClass( "ui-spinner-up" ) ? 1 : -1, event );
16924 "mouseup .ui-spinner-button": "_stop",
16925 "mouseenter .ui-spinner-button": function( event ) {
16927 // button will add ui-state-active if mouse was down while mouseleave and kept down
16928 if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
16932 if ( this._start( event ) === false ) {
16935 this._repeat( null, $( event.currentTarget )
16936 .hasClass( "ui-spinner-up" ) ? 1 : -1, event );
16939 // TODO: do we really want to consider this a stop?
16940 // shouldn't we just stop the repeater and wait until mouseup before
16941 // we trigger the stop event?
16942 "mouseleave .ui-spinner-button": "_stop"
16945 // Support mobile enhanced option and make backcompat more sane
16946 _enhance: function() {
16947 this.uiSpinner = this.element
16948 .attr( "autocomplete", "off" )
16958 _draw: function() {
16961 this._addClass( this.uiSpinner, "ui-spinner", "ui-widget ui-widget-content" );
16962 this._addClass( "ui-spinner-input" );
16964 this.element.attr( "role", "spinbutton" );
16967 this.buttons = this.uiSpinner.children( "a" )
16968 .attr( "tabIndex", -1 )
16969 .attr( "aria-hidden", true )
16976 // TODO: Right now button does not support classes this is already updated in button PR
16977 this._removeClass( this.buttons, "ui-corner-all" );
16979 this._addClass( this.buttons.first(), "ui-spinner-button ui-spinner-up" );
16980 this._addClass( this.buttons.last(), "ui-spinner-button ui-spinner-down" );
16981 this.buttons.first().button( {
16982 "icon": this.options.icons.up,
16985 this.buttons.last().button( {
16986 "icon": this.options.icons.down,
16990 // IE 6 doesn't understand height: 50% for the buttons
16991 // unless the wrapper has an explicit height
16992 if ( this.buttons.height() > Math.ceil( this.uiSpinner.height() * 0.5 ) &&
16993 this.uiSpinner.height() > 0 ) {
16994 this.uiSpinner.height( this.uiSpinner.height() );
16998 _keydown: function( event ) {
16999 var options = this.options,
17000 keyCode = $.ui.keyCode;
17002 switch ( event.keyCode ) {
17004 this._repeat( null, 1, event );
17007 this._repeat( null, -1, event );
17009 case keyCode.PAGE_UP:
17010 this._repeat( null, options.page, event );
17012 case keyCode.PAGE_DOWN:
17013 this._repeat( null, -options.page, event );
17020 _start: function( event ) {
17021 if ( !this.spinning && this._trigger( "start", event ) === false ) {
17025 if ( !this.counter ) {
17028 this.spinning = true;
17032 _repeat: function( i, steps, event ) {
17035 clearTimeout( this.timer );
17036 this.timer = this._delay( function() {
17037 this._repeat( 40, steps, event );
17040 this._spin( steps * this.options.step, event );
17043 _spin: function( step, event ) {
17044 var value = this.value() || 0;
17046 if ( !this.counter ) {
17050 value = this._adjustValue( value + step * this._increment( this.counter ) );
17052 if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false ) {
17053 this._value( value );
17058 _increment: function( i ) {
17059 var incremental = this.options.incremental;
17061 if ( incremental ) {
17062 return $.isFunction( incremental ) ?
17064 Math.floor( i * i * i / 50000 - i * i / 500 + 17 * i / 200 + 1 );
17070 _precision: function() {
17071 var precision = this._precisionOf( this.options.step );
17072 if ( this.options.min !== null ) {
17073 precision = Math.max( precision, this._precisionOf( this.options.min ) );
17078 _precisionOf: function( num ) {
17079 var str = num.toString(),
17080 decimal = str.indexOf( "." );
17081 return decimal === -1 ? 0 : str.length - decimal - 1;
17084 _adjustValue: function( value ) {
17085 var base, aboveMin,
17086 options = this.options;
17088 // Make sure we're at a valid step
17089 // - find out where we are relative to the base (min or 0)
17090 base = options.min !== null ? options.min : 0;
17091 aboveMin = value - base;
17093 // - round to the nearest step
17094 aboveMin = Math.round( aboveMin / options.step ) * options.step;
17096 // - rounding is based on 0, so adjust back to our base
17097 value = base + aboveMin;
17099 // Fix precision from bad JS floating point math
17100 value = parseFloat( value.toFixed( this._precision() ) );
17103 if ( options.max !== null && value > options.max ) {
17104 return options.max;
17106 if ( options.min !== null && value < options.min ) {
17107 return options.min;
17113 _stop: function( event ) {
17114 if ( !this.spinning ) {
17118 clearTimeout( this.timer );
17119 clearTimeout( this.mousewheelTimer );
17121 this.spinning = false;
17122 this._trigger( "stop", event );
17125 _setOption: function( key, value ) {
17126 var prevValue, first, last;
17128 if ( key === "culture" || key === "numberFormat" ) {
17129 prevValue = this._parse( this.element.val() );
17130 this.options[ key ] = value;
17131 this.element.val( this._format( prevValue ) );
17135 if ( key === "max" || key === "min" || key === "step" ) {
17136 if ( typeof value === "string" ) {
17137 value = this._parse( value );
17140 if ( key === "icons" ) {
17141 first = this.buttons.first().find( ".ui-icon" );
17142 this._removeClass( first, null, this.options.icons.up );
17143 this._addClass( first, null, value.up );
17144 last = this.buttons.last().find( ".ui-icon" );
17145 this._removeClass( last, null, this.options.icons.down );
17146 this._addClass( last, null, value.down );
17149 this._super( key, value );
17152 _setOptionDisabled: function( value ) {
17153 this._super( value );
17155 this._toggleClass( this.uiSpinner, null, "ui-state-disabled", !!value );
17156 this.element.prop( "disabled", !!value );
17157 this.buttons.button( value ? "disable" : "enable" );
17160 _setOptions: spinnerModifer( function( options ) {
17161 this._super( options );
17164 _parse: function( val ) {
17165 if ( typeof val === "string" && val !== "" ) {
17166 val = window.Globalize && this.options.numberFormat ?
17167 Globalize.parseFloat( val, 10, this.options.culture ) : +val;
17169 return val === "" || isNaN( val ) ? null : val;
17172 _format: function( value ) {
17173 if ( value === "" ) {
17176 return window.Globalize && this.options.numberFormat ?
17177 Globalize.format( value, this.options.numberFormat, this.options.culture ) :
17181 _refresh: function() {
17182 this.element.attr( {
17183 "aria-valuemin": this.options.min,
17184 "aria-valuemax": this.options.max,
17186 // TODO: what should we do with values that can't be parsed?
17187 "aria-valuenow": this._parse( this.element.val() )
17191 isValid: function() {
17192 var value = this.value();
17195 if ( value === null ) {
17199 // If value gets adjusted, it's invalid
17200 return value === this._adjustValue( value );
17203 // Update the value without triggering change
17204 _value: function( value, allowAny ) {
17206 if ( value !== "" ) {
17207 parsed = this._parse( value );
17208 if ( parsed !== null ) {
17210 parsed = this._adjustValue( parsed );
17212 value = this._format( parsed );
17215 this.element.val( value );
17219 _destroy: function() {
17221 .prop( "disabled", false )
17222 .removeAttr( "autocomplete role aria-valuemin aria-valuemax aria-valuenow" );
17224 this.uiSpinner.replaceWith( this.element );
17227 stepUp: spinnerModifer( function( steps ) {
17228 this._stepUp( steps );
17230 _stepUp: function( steps ) {
17231 if ( this._start() ) {
17232 this._spin( ( steps || 1 ) * this.options.step );
17237 stepDown: spinnerModifer( function( steps ) {
17238 this._stepDown( steps );
17240 _stepDown: function( steps ) {
17241 if ( this._start() ) {
17242 this._spin( ( steps || 1 ) * -this.options.step );
17247 pageUp: spinnerModifer( function( pages ) {
17248 this._stepUp( ( pages || 1 ) * this.options.page );
17251 pageDown: spinnerModifer( function( pages ) {
17252 this._stepDown( ( pages || 1 ) * this.options.page );
17255 value: function( newVal ) {
17256 if ( !arguments.length ) {
17257 return this._parse( this.element.val() );
17259 spinnerModifer( this._value ).call( this, newVal );
17262 widget: function() {
17263 return this.uiSpinner;
17268 // TODO: switch return back to widget declaration at top of file when this is removed
17269 if ( $.uiBackCompat !== false ) {
17271 // Backcompat for spinner html extension points
17272 $.widget( "ui.spinner", $.ui.spinner, {
17273 _enhance: function() {
17274 this.uiSpinner = this.element
17275 .attr( "autocomplete", "off" )
17276 .wrap( this._uiSpinnerHtml() )
17280 .append( this._buttonHtml() );
17282 _uiSpinnerHtml: function() {
17286 _buttonHtml: function() {
17287 return "<a></a><a></a>";
17292 var widgetsSpinner = $.ui.spinner;
17296 * jQuery UI Tabs 1.12.1
17297 * http://jqueryui.com
17299 * Copyright jQuery Foundation and other contributors
17300 * Released under the MIT license.
17301 * http://jquery.org/license
17306 //>>description: Transforms a set of container elements into a tab structure.
17307 //>>docs: http://api.jqueryui.com/tabs/
17308 //>>demos: http://jqueryui.com/tabs/
17309 //>>css.structure: ../../themes/base/core.css
17310 //>>css.structure: ../../themes/base/tabs.css
17311 //>>css.theme: ../../themes/base/theme.css
17315 $.widget( "ui.tabs", {
17321 "ui-tabs": "ui-corner-all",
17322 "ui-tabs-nav": "ui-corner-all",
17323 "ui-tabs-panel": "ui-corner-bottom",
17324 "ui-tabs-tab": "ui-corner-top"
17326 collapsible: false,
17328 heightStyle: "content",
17334 beforeActivate: null,
17339 _isLocal: ( function() {
17340 var rhash = /#.*$/;
17342 return function( anchor ) {
17343 var anchorUrl, locationUrl;
17345 anchorUrl = anchor.href.replace( rhash, "" );
17346 locationUrl = location.href.replace( rhash, "" );
17348 // Decoding may throw an error if the URL isn't UTF-8 (#9518)
17350 anchorUrl = decodeURIComponent( anchorUrl );
17351 } catch ( error ) {}
17353 locationUrl = decodeURIComponent( locationUrl );
17354 } catch ( error ) {}
17356 return anchor.hash.length > 1 && anchorUrl === locationUrl;
17360 _create: function() {
17362 options = this.options;
17364 this.running = false;
17366 this._addClass( "ui-tabs", "ui-widget ui-widget-content" );
17367 this._toggleClass( "ui-tabs-collapsible", null, options.collapsible );
17369 this._processTabs();
17370 options.active = this._initialActive();
17372 // Take disabling tabs via class attribute from HTML
17373 // into account and update option properly.
17374 if ( $.isArray( options.disabled ) ) {
17375 options.disabled = $.unique( options.disabled.concat(
17376 $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
17377 return that.tabs.index( li );
17382 // Check for length avoids error when initializing empty list
17383 if ( this.options.active !== false && this.anchors.length ) {
17384 this.active = this._findActive( options.active );
17391 if ( this.active.length ) {
17392 this.load( options.active );
17396 _initialActive: function() {
17397 var active = this.options.active,
17398 collapsible = this.options.collapsible,
17399 locationHash = location.hash.substring( 1 );
17401 if ( active === null ) {
17403 // check the fragment identifier in the URL
17404 if ( locationHash ) {
17405 this.tabs.each( function( i, tab ) {
17406 if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
17413 // Check for a tab marked active via a class
17414 if ( active === null ) {
17415 active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
17418 // No active tab, set to false
17419 if ( active === null || active === -1 ) {
17420 active = this.tabs.length ? 0 : false;
17424 // Handle numbers: negative, out of range
17425 if ( active !== false ) {
17426 active = this.tabs.index( this.tabs.eq( active ) );
17427 if ( active === -1 ) {
17428 active = collapsible ? false : 0;
17432 // Don't allow collapsible: false and active: false
17433 if ( !collapsible && active === false && this.anchors.length ) {
17440 _getCreateEventData: function() {
17443 panel: !this.active.length ? $() : this._getPanelForTab( this.active )
17447 _tabKeydown: function( event ) {
17448 var focusedTab = $( $.ui.safeActiveElement( this.document[ 0 ] ) ).closest( "li" ),
17449 selectedIndex = this.tabs.index( focusedTab ),
17450 goingForward = true;
17452 if ( this._handlePageNav( event ) ) {
17456 switch ( event.keyCode ) {
17457 case $.ui.keyCode.RIGHT:
17458 case $.ui.keyCode.DOWN:
17461 case $.ui.keyCode.UP:
17462 case $.ui.keyCode.LEFT:
17463 goingForward = false;
17466 case $.ui.keyCode.END:
17467 selectedIndex = this.anchors.length - 1;
17469 case $.ui.keyCode.HOME:
17472 case $.ui.keyCode.SPACE:
17474 // Activate only, no collapsing
17475 event.preventDefault();
17476 clearTimeout( this.activating );
17477 this._activate( selectedIndex );
17479 case $.ui.keyCode.ENTER:
17481 // Toggle (cancel delayed activation, allow collapsing)
17482 event.preventDefault();
17483 clearTimeout( this.activating );
17485 // Determine if we should collapse or activate
17486 this._activate( selectedIndex === this.options.active ? false : selectedIndex );
17492 // Focus the appropriate tab, based on which key was pressed
17493 event.preventDefault();
17494 clearTimeout( this.activating );
17495 selectedIndex = this._focusNextTab( selectedIndex, goingForward );
17497 // Navigating with control/command key will prevent automatic activation
17498 if ( !event.ctrlKey && !event.metaKey ) {
17500 // Update aria-selected immediately so that AT think the tab is already selected.
17501 // Otherwise AT may confuse the user by stating that they need to activate the tab,
17502 // but the tab will already be activated by the time the announcement finishes.
17503 focusedTab.attr( "aria-selected", "false" );
17504 this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
17506 this.activating = this._delay( function() {
17507 this.option( "active", selectedIndex );
17512 _panelKeydown: function( event ) {
17513 if ( this._handlePageNav( event ) ) {
17517 // Ctrl+up moves focus to the current tab
17518 if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
17519 event.preventDefault();
17520 this.active.trigger( "focus" );
17524 // Alt+page up/down moves focus to the previous/next tab (and activates)
17525 _handlePageNav: function( event ) {
17526 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
17527 this._activate( this._focusNextTab( this.options.active - 1, false ) );
17530 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
17531 this._activate( this._focusNextTab( this.options.active + 1, true ) );
17536 _findNextTab: function( index, goingForward ) {
17537 var lastTabIndex = this.tabs.length - 1;
17539 function constrain() {
17540 if ( index > lastTabIndex ) {
17544 index = lastTabIndex;
17549 while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
17550 index = goingForward ? index + 1 : index - 1;
17556 _focusNextTab: function( index, goingForward ) {
17557 index = this._findNextTab( index, goingForward );
17558 this.tabs.eq( index ).trigger( "focus" );
17562 _setOption: function( key, value ) {
17563 if ( key === "active" ) {
17565 // _activate() will handle invalid values and update this.options
17566 this._activate( value );
17570 this._super( key, value );
17572 if ( key === "collapsible" ) {
17573 this._toggleClass( "ui-tabs-collapsible", null, value );
17575 // Setting collapsible: false while collapsed; open first panel
17576 if ( !value && this.options.active === false ) {
17577 this._activate( 0 );
17581 if ( key === "event" ) {
17582 this._setupEvents( value );
17585 if ( key === "heightStyle" ) {
17586 this._setupHeightStyle( value );
17590 _sanitizeSelector: function( hash ) {
17591 return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
17594 refresh: function() {
17595 var options = this.options,
17596 lis = this.tablist.children( ":has(a[href])" );
17598 // Get disabled tabs from class attribute from HTML
17599 // this will get converted to a boolean if needed in _refresh()
17600 options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
17601 return lis.index( tab );
17604 this._processTabs();
17606 // Was collapsed or no tabs
17607 if ( options.active === false || !this.anchors.length ) {
17608 options.active = false;
17611 // was active, but active tab is gone
17612 } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
17614 // all remaining tabs are disabled
17615 if ( this.tabs.length === options.disabled.length ) {
17616 options.active = false;
17619 // activate previous tab
17621 this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
17624 // was active, active tab still exists
17627 // make sure active index is correct
17628 options.active = this.tabs.index( this.active );
17634 _refresh: function() {
17635 this._setOptionDisabled( this.options.disabled );
17636 this._setupEvents( this.options.event );
17637 this._setupHeightStyle( this.options.heightStyle );
17639 this.tabs.not( this.active ).attr( {
17640 "aria-selected": "false",
17641 "aria-expanded": "false",
17644 this.panels.not( this._getPanelForTab( this.active ) )
17647 "aria-hidden": "true"
17650 // Make sure one tab is in the tab order
17651 if ( !this.active.length ) {
17652 this.tabs.eq( 0 ).attr( "tabIndex", 0 );
17656 "aria-selected": "true",
17657 "aria-expanded": "true",
17660 this._addClass( this.active, "ui-tabs-active", "ui-state-active" );
17661 this._getPanelForTab( this.active )
17664 "aria-hidden": "false"
17669 _processTabs: function() {
17671 prevTabs = this.tabs,
17672 prevAnchors = this.anchors,
17673 prevPanels = this.panels;
17675 this.tablist = this._getList().attr( "role", "tablist" );
17676 this._addClass( this.tablist, "ui-tabs-nav",
17677 "ui-helper-reset ui-helper-clearfix ui-widget-header" );
17679 // Prevent users from focusing disabled tabs via click
17681 .on( "mousedown" + this.eventNamespace, "> li", function( event ) {
17682 if ( $( this ).is( ".ui-state-disabled" ) ) {
17683 event.preventDefault();
17688 // Preventing the default action in mousedown doesn't prevent IE
17689 // from focusing the element, so if the anchor gets focused, blur.
17690 // We don't have to worry about focusing the previously focused
17691 // element since clicking on a non-focusable element should focus
17692 // the body anyway.
17693 .on( "focus" + this.eventNamespace, ".ui-tabs-anchor", function() {
17694 if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
17699 this.tabs = this.tablist.find( "> li:has(a[href])" )
17704 this._addClass( this.tabs, "ui-tabs-tab", "ui-state-default" );
17706 this.anchors = this.tabs.map( function() {
17707 return $( "a", this )[ 0 ];
17710 role: "presentation",
17713 this._addClass( this.anchors, "ui-tabs-anchor" );
17717 this.anchors.each( function( i, anchor ) {
17718 var selector, panel, panelId,
17719 anchorId = $( anchor ).uniqueId().attr( "id" ),
17720 tab = $( anchor ).closest( "li" ),
17721 originalAriaControls = tab.attr( "aria-controls" );
17724 if ( that._isLocal( anchor ) ) {
17725 selector = anchor.hash;
17726 panelId = selector.substring( 1 );
17727 panel = that.element.find( that._sanitizeSelector( selector ) );
17732 // If the tab doesn't already have aria-controls,
17733 // generate an id by using a throw-away element
17734 panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id;
17735 selector = "#" + panelId;
17736 panel = that.element.find( selector );
17737 if ( !panel.length ) {
17738 panel = that._createPanel( panelId );
17739 panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
17741 panel.attr( "aria-live", "polite" );
17744 if ( panel.length ) {
17745 that.panels = that.panels.add( panel );
17747 if ( originalAriaControls ) {
17748 tab.data( "ui-tabs-aria-controls", originalAriaControls );
17751 "aria-controls": panelId,
17752 "aria-labelledby": anchorId
17754 panel.attr( "aria-labelledby", anchorId );
17757 this.panels.attr( "role", "tabpanel" );
17758 this._addClass( this.panels, "ui-tabs-panel", "ui-widget-content" );
17760 // Avoid memory leaks (#10056)
17762 this._off( prevTabs.not( this.tabs ) );
17763 this._off( prevAnchors.not( this.anchors ) );
17764 this._off( prevPanels.not( this.panels ) );
17768 // Allow overriding how to find the list for rare usage scenarios (#7715)
17769 _getList: function() {
17770 return this.tablist || this.element.find( "ol, ul" ).eq( 0 );
17773 _createPanel: function( id ) {
17774 return $( "<div>" )
17776 .data( "ui-tabs-destroy", true );
17779 _setOptionDisabled: function( disabled ) {
17780 var currentItem, li, i;
17782 if ( $.isArray( disabled ) ) {
17783 if ( !disabled.length ) {
17785 } else if ( disabled.length === this.anchors.length ) {
17791 for ( i = 0; ( li = this.tabs[ i ] ); i++ ) {
17792 currentItem = $( li );
17793 if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
17794 currentItem.attr( "aria-disabled", "true" );
17795 this._addClass( currentItem, null, "ui-state-disabled" );
17797 currentItem.removeAttr( "aria-disabled" );
17798 this._removeClass( currentItem, null, "ui-state-disabled" );
17802 this.options.disabled = disabled;
17804 this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null,
17805 disabled === true );
17808 _setupEvents: function( event ) {
17811 $.each( event.split( " " ), function( index, eventName ) {
17812 events[ eventName ] = "_eventHandler";
17816 this._off( this.anchors.add( this.tabs ).add( this.panels ) );
17818 // Always prevent the default action, even when disabled
17819 this._on( true, this.anchors, {
17820 click: function( event ) {
17821 event.preventDefault();
17824 this._on( this.anchors, events );
17825 this._on( this.tabs, { keydown: "_tabKeydown" } );
17826 this._on( this.panels, { keydown: "_panelKeydown" } );
17828 this._focusable( this.tabs );
17829 this._hoverable( this.tabs );
17832 _setupHeightStyle: function( heightStyle ) {
17834 parent = this.element.parent();
17836 if ( heightStyle === "fill" ) {
17837 maxHeight = parent.height();
17838 maxHeight -= this.element.outerHeight() - this.element.height();
17840 this.element.siblings( ":visible" ).each( function() {
17841 var elem = $( this ),
17842 position = elem.css( "position" );
17844 if ( position === "absolute" || position === "fixed" ) {
17847 maxHeight -= elem.outerHeight( true );
17850 this.element.children().not( this.panels ).each( function() {
17851 maxHeight -= $( this ).outerHeight( true );
17854 this.panels.each( function() {
17855 $( this ).height( Math.max( 0, maxHeight -
17856 $( this ).innerHeight() + $( this ).height() ) );
17858 .css( "overflow", "auto" );
17859 } else if ( heightStyle === "auto" ) {
17861 this.panels.each( function() {
17862 maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
17863 } ).height( maxHeight );
17867 _eventHandler: function( event ) {
17868 var options = this.options,
17869 active = this.active,
17870 anchor = $( event.currentTarget ),
17871 tab = anchor.closest( "li" ),
17872 clickedIsActive = tab[ 0 ] === active[ 0 ],
17873 collapsing = clickedIsActive && options.collapsible,
17874 toShow = collapsing ? $() : this._getPanelForTab( tab ),
17875 toHide = !active.length ? $() : this._getPanelForTab( active ),
17879 newTab: collapsing ? $() : tab,
17883 event.preventDefault();
17885 if ( tab.hasClass( "ui-state-disabled" ) ||
17887 // tab is already loading
17888 tab.hasClass( "ui-tabs-loading" ) ||
17890 // can't switch durning an animation
17893 // click on active header, but not collapsible
17894 ( clickedIsActive && !options.collapsible ) ||
17896 // allow canceling activation
17897 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
17901 options.active = collapsing ? false : this.tabs.index( tab );
17903 this.active = clickedIsActive ? $() : tab;
17908 if ( !toHide.length && !toShow.length ) {
17909 $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
17912 if ( toShow.length ) {
17913 this.load( this.tabs.index( tab ), event );
17915 this._toggle( event, eventData );
17918 // Handles show/hide for selecting tabs
17919 _toggle: function( event, eventData ) {
17921 toShow = eventData.newPanel,
17922 toHide = eventData.oldPanel;
17924 this.running = true;
17926 function complete() {
17927 that.running = false;
17928 that._trigger( "activate", event, eventData );
17932 that._addClass( eventData.newTab.closest( "li" ), "ui-tabs-active", "ui-state-active" );
17934 if ( toShow.length && that.options.show ) {
17935 that._show( toShow, that.options.show, complete );
17942 // Start out by hiding, then showing, then completing
17943 if ( toHide.length && this.options.hide ) {
17944 this._hide( toHide, this.options.hide, function() {
17945 that._removeClass( eventData.oldTab.closest( "li" ),
17946 "ui-tabs-active", "ui-state-active" );
17950 this._removeClass( eventData.oldTab.closest( "li" ),
17951 "ui-tabs-active", "ui-state-active" );
17956 toHide.attr( "aria-hidden", "true" );
17957 eventData.oldTab.attr( {
17958 "aria-selected": "false",
17959 "aria-expanded": "false"
17962 // If we're switching tabs, remove the old tab from the tab order.
17963 // If we're opening from collapsed state, remove the previous tab from the tab order.
17964 // If we're collapsing, then keep the collapsing tab in the tab order.
17965 if ( toShow.length && toHide.length ) {
17966 eventData.oldTab.attr( "tabIndex", -1 );
17967 } else if ( toShow.length ) {
17968 this.tabs.filter( function() {
17969 return $( this ).attr( "tabIndex" ) === 0;
17971 .attr( "tabIndex", -1 );
17974 toShow.attr( "aria-hidden", "false" );
17975 eventData.newTab.attr( {
17976 "aria-selected": "true",
17977 "aria-expanded": "true",
17982 _activate: function( index ) {
17984 active = this._findActive( index );
17986 // Trying to activate the already active panel
17987 if ( active[ 0 ] === this.active[ 0 ] ) {
17991 // Trying to collapse, simulate a click on the current active header
17992 if ( !active.length ) {
17993 active = this.active;
17996 anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
17997 this._eventHandler( {
17999 currentTarget: anchor,
18000 preventDefault: $.noop
18004 _findActive: function( index ) {
18005 return index === false ? $() : this.tabs.eq( index );
18008 _getIndex: function( index ) {
18010 // meta-function to give users option to provide a href string instead of a numerical index.
18011 if ( typeof index === "string" ) {
18012 index = this.anchors.index( this.anchors.filter( "[href$='" +
18013 $.ui.escapeSelector( index ) + "']" ) );
18019 _destroy: function() {
18025 .removeAttr( "role" )
18026 .off( this.eventNamespace );
18029 .removeAttr( "role tabIndex" )
18032 this.tabs.add( this.panels ).each( function() {
18033 if ( $.data( this, "ui-tabs-destroy" ) ) {
18034 $( this ).remove();
18036 $( this ).removeAttr( "role tabIndex " +
18037 "aria-live aria-busy aria-selected aria-labelledby aria-hidden aria-expanded" );
18041 this.tabs.each( function() {
18042 var li = $( this ),
18043 prev = li.data( "ui-tabs-aria-controls" );
18046 .attr( "aria-controls", prev )
18047 .removeData( "ui-tabs-aria-controls" );
18049 li.removeAttr( "aria-controls" );
18053 this.panels.show();
18055 if ( this.options.heightStyle !== "content" ) {
18056 this.panels.css( "height", "" );
18060 enable: function( index ) {
18061 var disabled = this.options.disabled;
18062 if ( disabled === false ) {
18066 if ( index === undefined ) {
18069 index = this._getIndex( index );
18070 if ( $.isArray( disabled ) ) {
18071 disabled = $.map( disabled, function( num ) {
18072 return num !== index ? num : null;
18075 disabled = $.map( this.tabs, function( li, num ) {
18076 return num !== index ? num : null;
18080 this._setOptionDisabled( disabled );
18083 disable: function( index ) {
18084 var disabled = this.options.disabled;
18085 if ( disabled === true ) {
18089 if ( index === undefined ) {
18092 index = this._getIndex( index );
18093 if ( $.inArray( index, disabled ) !== -1 ) {
18096 if ( $.isArray( disabled ) ) {
18097 disabled = $.merge( [ index ], disabled ).sort();
18099 disabled = [ index ];
18102 this._setOptionDisabled( disabled );
18105 load: function( index, event ) {
18106 index = this._getIndex( index );
18108 tab = this.tabs.eq( index ),
18109 anchor = tab.find( ".ui-tabs-anchor" ),
18110 panel = this._getPanelForTab( tab ),
18115 complete = function( jqXHR, status ) {
18116 if ( status === "abort" ) {
18117 that.panels.stop( false, true );
18120 that._removeClass( tab, "ui-tabs-loading" );
18121 panel.removeAttr( "aria-busy" );
18123 if ( jqXHR === that.xhr ) {
18129 if ( this._isLocal( anchor[ 0 ] ) ) {
18133 this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
18135 // Support: jQuery <1.8
18136 // jQuery <1.8 returns false if the request is canceled in beforeSend,
18137 // but as of 1.8, $.ajax() always returns a jqXHR object.
18138 if ( this.xhr && this.xhr.statusText !== "canceled" ) {
18139 this._addClass( tab, "ui-tabs-loading" );
18140 panel.attr( "aria-busy", "true" );
18143 .done( function( response, status, jqXHR ) {
18145 // support: jQuery <1.8
18146 // http://bugs.jquery.com/ticket/11778
18147 setTimeout( function() {
18148 panel.html( response );
18149 that._trigger( "load", event, eventData );
18151 complete( jqXHR, status );
18154 .fail( function( jqXHR, status ) {
18156 // support: jQuery <1.8
18157 // http://bugs.jquery.com/ticket/11778
18158 setTimeout( function() {
18159 complete( jqXHR, status );
18165 _ajaxSettings: function( anchor, event, eventData ) {
18169 // Support: IE <11 only
18170 // Strip any hash that exists to prevent errors with the Ajax request
18171 url: anchor.attr( "href" ).replace( /#.*$/, "" ),
18172 beforeSend: function( jqXHR, settings ) {
18173 return that._trigger( "beforeLoad", event,
18174 $.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) );
18179 _getPanelForTab: function( tab ) {
18180 var id = $( tab ).attr( "aria-controls" );
18181 return this.element.find( this._sanitizeSelector( "#" + id ) );
18186 // TODO: Switch return back to widget declaration at top of file when this is removed
18187 if ( $.uiBackCompat !== false ) {
18189 // Backcompat for ui-tab class (now ui-tabs-tab)
18190 $.widget( "ui.tabs", $.ui.tabs, {
18191 _processTabs: function() {
18192 this._superApply( arguments );
18193 this._addClass( this.tabs, "ui-tab" );
18198 var widgetsTabs = $.ui.tabs;
18202 * jQuery UI Tooltip 1.12.1
18203 * http://jqueryui.com
18205 * Copyright jQuery Foundation and other contributors
18206 * Released under the MIT license.
18207 * http://jquery.org/license
18212 //>>description: Shows additional information for any element on hover or focus.
18213 //>>docs: http://api.jqueryui.com/tooltip/
18214 //>>demos: http://jqueryui.com/tooltip/
18215 //>>css.structure: ../../themes/base/core.css
18216 //>>css.structure: ../../themes/base/tooltip.css
18217 //>>css.theme: ../../themes/base/theme.css
18221 $.widget( "ui.tooltip", {
18225 "ui-tooltip": "ui-corner-all ui-widget-shadow"
18227 content: function() {
18229 // support: IE<9, Opera in jQuery <1.7
18230 // .text() can't accept undefined, so coerce to a string
18231 var title = $( this ).attr( "title" ) || "";
18233 // Escape title, since we're going from an attribute to raw HTML
18234 return $( "<a>" ).text( title ).html();
18238 // Disabled elements have inconsistent behavior across browsers (#8661)
18239 items: "[title]:not([disabled])",
18243 collision: "flipfit flip"
18253 _addDescribedBy: function( elem, id ) {
18254 var describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ );
18255 describedby.push( id );
18257 .data( "ui-tooltip-id", id )
18258 .attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
18261 _removeDescribedBy: function( elem ) {
18262 var id = elem.data( "ui-tooltip-id" ),
18263 describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ ),
18264 index = $.inArray( id, describedby );
18266 if ( index !== -1 ) {
18267 describedby.splice( index, 1 );
18270 elem.removeData( "ui-tooltip-id" );
18271 describedby = $.trim( describedby.join( " " ) );
18272 if ( describedby ) {
18273 elem.attr( "aria-describedby", describedby );
18275 elem.removeAttr( "aria-describedby" );
18279 _create: function() {
18285 // IDs of generated tooltips, needed for destroy
18286 this.tooltips = {};
18288 // IDs of parent tooltips where we removed the title attribute
18291 // Append the aria-live region so tooltips announce correctly
18292 this.liveRegion = $( "<div>" )
18295 "aria-live": "assertive",
18296 "aria-relevant": "additions"
18298 .appendTo( this.document[ 0 ].body );
18299 this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" );
18301 this.disabledTitles = $( [] );
18304 _setOption: function( key, value ) {
18307 this._super( key, value );
18309 if ( key === "content" ) {
18310 $.each( this.tooltips, function( id, tooltipData ) {
18311 that._updateContent( tooltipData.element );
18316 _setOptionDisabled: function( value ) {
18317 this[ value ? "_disable" : "_enable" ]();
18320 _disable: function() {
18323 // Close open tooltips
18324 $.each( this.tooltips, function( id, tooltipData ) {
18325 var event = $.Event( "blur" );
18326 event.target = event.currentTarget = tooltipData.element[ 0 ];
18327 that.close( event, true );
18330 // Remove title attributes to prevent native tooltips
18331 this.disabledTitles = this.disabledTitles.add(
18332 this.element.find( this.options.items ).addBack()
18333 .filter( function() {
18334 var element = $( this );
18335 if ( element.is( "[title]" ) ) {
18337 .data( "ui-tooltip-title", element.attr( "title" ) )
18338 .removeAttr( "title" );
18344 _enable: function() {
18346 // restore title attributes
18347 this.disabledTitles.each( function() {
18348 var element = $( this );
18349 if ( element.data( "ui-tooltip-title" ) ) {
18350 element.attr( "title", element.data( "ui-tooltip-title" ) );
18353 this.disabledTitles = $( [] );
18356 open: function( event ) {
18358 target = $( event ? event.target : this.element )
18360 // we need closest here due to mouseover bubbling,
18361 // but always pointing at the same event target
18362 .closest( this.options.items );
18364 // No element to show a tooltip for or the tooltip is already open
18365 if ( !target.length || target.data( "ui-tooltip-id" ) ) {
18369 if ( target.attr( "title" ) ) {
18370 target.data( "ui-tooltip-title", target.attr( "title" ) );
18373 target.data( "ui-tooltip-open", true );
18375 // Kill parent tooltips, custom or native, for hover
18376 if ( event && event.type === "mouseover" ) {
18377 target.parents().each( function() {
18378 var parent = $( this ),
18380 if ( parent.data( "ui-tooltip-open" ) ) {
18381 blurEvent = $.Event( "blur" );
18382 blurEvent.target = blurEvent.currentTarget = this;
18383 that.close( blurEvent, true );
18385 if ( parent.attr( "title" ) ) {
18387 that.parents[ this.id ] = {
18389 title: parent.attr( "title" )
18391 parent.attr( "title", "" );
18396 this._registerCloseHandlers( event, target );
18397 this._updateContent( target, event );
18400 _updateContent: function( target, event ) {
18402 contentOption = this.options.content,
18404 eventType = event ? event.type : null;
18406 if ( typeof contentOption === "string" || contentOption.nodeType ||
18407 contentOption.jquery ) {
18408 return this._open( event, target, contentOption );
18411 content = contentOption.call( target[ 0 ], function( response ) {
18413 // IE may instantly serve a cached response for ajax requests
18414 // delay this call to _open so the other call to _open runs first
18415 that._delay( function() {
18417 // Ignore async response if tooltip was closed already
18418 if ( !target.data( "ui-tooltip-open" ) ) {
18422 // JQuery creates a special event for focusin when it doesn't
18423 // exist natively. To improve performance, the native event
18424 // object is reused and the type is changed. Therefore, we can't
18425 // rely on the type being correct after the event finished
18426 // bubbling, so we set it back to the previous value. (#8740)
18428 event.type = eventType;
18430 this._open( event, target, response );
18434 this._open( event, target, content );
18438 _open: function( event, target, content ) {
18439 var tooltipData, tooltip, delayedShow, a11yContent,
18440 positionOption = $.extend( {}, this.options.position );
18446 // Content can be updated multiple times. If the tooltip already
18447 // exists, then just update the content and bail.
18448 tooltipData = this._find( target );
18449 if ( tooltipData ) {
18450 tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content );
18454 // If we have a title, clear it to prevent the native tooltip
18455 // we have to check first to avoid defining a title if none exists
18456 // (we don't want to cause an element to start matching [title])
18458 // We use removeAttr only for key events, to allow IE to export the correct
18459 // accessible attributes. For mouse events, set to empty string to avoid
18460 // native tooltip showing up (happens only when removing inside mouseover).
18461 if ( target.is( "[title]" ) ) {
18462 if ( event && event.type === "mouseover" ) {
18463 target.attr( "title", "" );
18465 target.removeAttr( "title" );
18469 tooltipData = this._tooltip( target );
18470 tooltip = tooltipData.tooltip;
18471 this._addDescribedBy( target, tooltip.attr( "id" ) );
18472 tooltip.find( ".ui-tooltip-content" ).html( content );
18474 // Support: Voiceover on OS X, JAWS on IE <= 9
18475 // JAWS announces deletions even when aria-relevant="additions"
18476 // Voiceover will sometimes re-read the entire log region's contents from the beginning
18477 this.liveRegion.children().hide();
18478 a11yContent = $( "<div>" ).html( tooltip.find( ".ui-tooltip-content" ).html() );
18479 a11yContent.removeAttr( "name" ).find( "[name]" ).removeAttr( "name" );
18480 a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" );
18481 a11yContent.appendTo( this.liveRegion );
18483 function position( event ) {
18484 positionOption.of = event;
18485 if ( tooltip.is( ":hidden" ) ) {
18488 tooltip.position( positionOption );
18490 if ( this.options.track && event && /^mouse/.test( event.type ) ) {
18491 this._on( this.document, {
18492 mousemove: position
18495 // trigger once to override element-relative positioning
18498 tooltip.position( $.extend( {
18500 }, this.options.position ) );
18505 this._show( tooltip, this.options.show );
18507 // Handle tracking tooltips that are shown with a delay (#8644). As soon
18508 // as the tooltip is visible, position the tooltip using the most recent
18510 // Adds the check to add the timers only when both delay and track options are set (#14682)
18511 if ( this.options.track && this.options.show && this.options.show.delay ) {
18512 delayedShow = this.delayedShow = setInterval( function() {
18513 if ( tooltip.is( ":visible" ) ) {
18514 position( positionOption.of );
18515 clearInterval( delayedShow );
18517 }, $.fx.interval );
18520 this._trigger( "open", event, { tooltip: tooltip } );
18523 _registerCloseHandlers: function( event, target ) {
18525 keyup: function( event ) {
18526 if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
18527 var fakeEvent = $.Event( event );
18528 fakeEvent.currentTarget = target[ 0 ];
18529 this.close( fakeEvent, true );
18534 // Only bind remove handler for delegated targets. Non-delegated
18535 // tooltips will handle this in destroy.
18536 if ( target[ 0 ] !== this.element[ 0 ] ) {
18537 events.remove = function() {
18538 this._removeTooltip( this._find( target ).tooltip );
18542 if ( !event || event.type === "mouseover" ) {
18543 events.mouseleave = "close";
18545 if ( !event || event.type === "focusin" ) {
18546 events.focusout = "close";
18548 this._on( true, target, events );
18551 close: function( event ) {
18554 target = $( event ? event.currentTarget : this.element ),
18555 tooltipData = this._find( target );
18557 // The tooltip may already be closed
18558 if ( !tooltipData ) {
18560 // We set ui-tooltip-open immediately upon open (in open()), but only set the
18561 // additional data once there's actually content to show (in _open()). So even if the
18562 // tooltip doesn't have full data, we always remove ui-tooltip-open in case we're in
18563 // the period between open() and _open().
18564 target.removeData( "ui-tooltip-open" );
18568 tooltip = tooltipData.tooltip;
18570 // Disabling closes the tooltip, so we need to track when we're closing
18571 // to avoid an infinite loop in case the tooltip becomes disabled on close
18572 if ( tooltipData.closing ) {
18576 // Clear the interval for delayed tracking tooltips
18577 clearInterval( this.delayedShow );
18579 // Only set title if we had one before (see comment in _open())
18580 // If the title attribute has changed since open(), don't restore
18581 if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) {
18582 target.attr( "title", target.data( "ui-tooltip-title" ) );
18585 this._removeDescribedBy( target );
18587 tooltipData.hiding = true;
18588 tooltip.stop( true );
18589 this._hide( tooltip, this.options.hide, function() {
18590 that._removeTooltip( $( this ) );
18593 target.removeData( "ui-tooltip-open" );
18594 this._off( target, "mouseleave focusout keyup" );
18596 // Remove 'remove' binding only on delegated targets
18597 if ( target[ 0 ] !== this.element[ 0 ] ) {
18598 this._off( target, "remove" );
18600 this._off( this.document, "mousemove" );
18602 if ( event && event.type === "mouseleave" ) {
18603 $.each( this.parents, function( id, parent ) {
18604 $( parent.element ).attr( "title", parent.title );
18605 delete that.parents[ id ];
18609 tooltipData.closing = true;
18610 this._trigger( "close", event, { tooltip: tooltip } );
18611 if ( !tooltipData.hiding ) {
18612 tooltipData.closing = false;
18616 _tooltip: function( element ) {
18617 var tooltip = $( "<div>" ).attr( "role", "tooltip" ),
18618 content = $( "<div>" ).appendTo( tooltip ),
18619 id = tooltip.uniqueId().attr( "id" );
18621 this._addClass( content, "ui-tooltip-content" );
18622 this._addClass( tooltip, "ui-tooltip", "ui-widget ui-widget-content" );
18624 tooltip.appendTo( this._appendTo( element ) );
18626 return this.tooltips[ id ] = {
18632 _find: function( target ) {
18633 var id = target.data( "ui-tooltip-id" );
18634 return id ? this.tooltips[ id ] : null;
18637 _removeTooltip: function( tooltip ) {
18639 delete this.tooltips[ tooltip.attr( "id" ) ];
18642 _appendTo: function( target ) {
18643 var element = target.closest( ".ui-front, dialog" );
18645 if ( !element.length ) {
18646 element = this.document[ 0 ].body;
18652 _destroy: function() {
18655 // Close open tooltips
18656 $.each( this.tooltips, function( id, tooltipData ) {
18658 // Delegate to close method to handle common cleanup
18659 var event = $.Event( "blur" ),
18660 element = tooltipData.element;
18661 event.target = event.currentTarget = element[ 0 ];
18662 that.close( event, true );
18664 // Remove immediately; destroying an open tooltip doesn't use the
18666 $( "#" + id ).remove();
18668 // Restore the title
18669 if ( element.data( "ui-tooltip-title" ) ) {
18671 // If the title attribute has changed since open(), don't restore
18672 if ( !element.attr( "title" ) ) {
18673 element.attr( "title", element.data( "ui-tooltip-title" ) );
18675 element.removeData( "ui-tooltip-title" );
18678 this.liveRegion.remove();
18683 // TODO: Switch return back to widget declaration at top of file when this is removed
18684 if ( $.uiBackCompat !== false ) {
18686 // Backcompat for tooltipClass option
18687 $.widget( "ui.tooltip", $.ui.tooltip, {
18691 _tooltip: function() {
18692 var tooltipData = this._superApply( arguments );
18693 if ( this.options.tooltipClass ) {
18694 tooltipData.tooltip.addClass( this.options.tooltipClass );
18696 return tooltipData;
18701 var widgetsTooltip = $.ui.tooltip;