1 /*! jQuery UI - v1.11.4 - 2016-02-22
3 * Includes: core.js, widget.js, mouse.js, position.js, draggable.js, droppable.js, sortable.js, accordion.js, autocomplete.js, button.js, datepicker.js, menu.js, progressbar.js, slider.js, tabs.js, effect.js, effect-highlight.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 );
18 * jQuery UI Core 1.11.4
21 * Copyright jQuery Foundation and other contributors
22 * Released under the MIT license.
23 * http://jquery.org/license
25 * http://api.jqueryui.com/category/ui-core/
29 // $.ui might exist from components with no dependencies, e.g., $.ui.position
57 scrollParent: function( includeHidden ) {
58 var position = this.css( "position" ),
59 excludeStaticParent = position === "absolute",
60 overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/,
61 scrollParent = this.parents().filter( function() {
62 var parent = $( this );
63 if ( excludeStaticParent && parent.css( "position" ) === "static" ) {
66 return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) + parent.css( "overflow-x" ) );
69 return position === "fixed" || !scrollParent.length ? $( this[ 0 ].ownerDocument || document ) : scrollParent;
72 uniqueId: (function() {
76 return this.each(function() {
78 this.id = "ui-id-" + ( ++uuid );
84 removeUniqueId: function() {
85 return this.each(function() {
86 if ( /^ui-id-\d+$/.test( this.id ) ) {
87 $( this ).removeAttr( "id" );
94 function focusable( element, isTabIndexNotNaN ) {
95 var map, mapName, img,
96 nodeName = element.nodeName.toLowerCase();
97 if ( "area" === nodeName ) {
98 map = element.parentNode;
100 if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
103 img = $( "img[usemap='#" + mapName + "']" )[ 0 ];
104 return !!img && visible( img );
106 return ( /^(input|select|textarea|button|object)$/.test( nodeName ) ?
109 element.href || isTabIndexNotNaN :
111 // the element and all of its ancestors must be visible
115 function visible( element ) {
116 return $.expr.filters.visible( element ) &&
117 !$( element ).parents().addBack().filter(function() {
118 return $.css( this, "visibility" ) === "hidden";
122 $.extend( $.expr[ ":" ], {
123 data: $.expr.createPseudo ?
124 $.expr.createPseudo(function( dataName ) {
125 return function( elem ) {
126 return !!$.data( elem, dataName );
129 // support: jQuery <1.8
130 function( elem, i, match ) {
131 return !!$.data( elem, match[ 3 ] );
134 focusable: function( element ) {
135 return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) );
138 tabbable: function( element ) {
139 var tabIndex = $.attr( element, "tabindex" ),
140 isTabIndexNaN = isNaN( tabIndex );
141 return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN );
145 // support: jQuery <1.8
146 if ( !$( "<a>" ).outerWidth( 1 ).jquery ) {
147 $.each( [ "Width", "Height" ], function( i, name ) {
148 var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
149 type = name.toLowerCase(),
151 innerWidth: $.fn.innerWidth,
152 innerHeight: $.fn.innerHeight,
153 outerWidth: $.fn.outerWidth,
154 outerHeight: $.fn.outerHeight
157 function reduce( elem, size, border, margin ) {
158 $.each( side, function() {
159 size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
161 size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
164 size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
170 $.fn[ "inner" + name ] = function( size ) {
171 if ( size === undefined ) {
172 return orig[ "inner" + name ].call( this );
175 return this.each(function() {
176 $( this ).css( type, reduce( this, size ) + "px" );
180 $.fn[ "outer" + name] = function( size, margin ) {
181 if ( typeof size !== "number" ) {
182 return orig[ "outer" + name ].call( this, size );
185 return this.each(function() {
186 $( this).css( type, reduce( this, size, true, margin ) + "px" );
192 // support: jQuery <1.8
193 if ( !$.fn.addBack ) {
194 $.fn.addBack = function( selector ) {
195 return this.add( selector == null ?
196 this.prevObject : this.prevObject.filter( selector )
201 // support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413)
202 if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) {
203 $.fn.removeData = (function( removeData ) {
204 return function( key ) {
205 if ( arguments.length ) {
206 return removeData.call( this, $.camelCase( key ) );
208 return removeData.call( this );
211 })( $.fn.removeData );
215 $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
218 focus: (function( orig ) {
219 return function( delay, fn ) {
220 return typeof delay === "number" ?
221 this.each(function() {
223 setTimeout(function() {
230 orig.apply( this, arguments );
234 disableSelection: (function() {
235 var eventType = "onselectstart" in document.createElement( "div" ) ?
240 return this.bind( eventType + ".ui-disableSelection", function( event ) {
241 event.preventDefault();
246 enableSelection: function() {
247 return this.unbind( ".ui-disableSelection" );
250 zIndex: function( zIndex ) {
251 if ( zIndex !== undefined ) {
252 return this.css( "zIndex", zIndex );
256 var elem = $( this[ 0 ] ), position, value;
257 while ( elem.length && elem[ 0 ] !== document ) {
258 // Ignore z-index if position is set to a value where z-index is ignored by the browser
259 // This makes behavior of this function consistent across browsers
260 // WebKit always returns auto if the element is positioned
261 position = elem.css( "position" );
262 if ( position === "absolute" || position === "relative" || position === "fixed" ) {
263 // IE returns 0 when zIndex is not specified
264 // other browsers return a string
265 // we ignore the case of nested elements with an explicit value of 0
266 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
267 value = parseInt( elem.css( "zIndex" ), 10 );
268 if ( !isNaN( value ) && value !== 0 ) {
272 elem = elem.parent();
280 // $.ui.plugin is deprecated. Use $.widget() extensions instead.
282 add: function( module, option, set ) {
284 proto = $.ui[ module ].prototype;
286 proto.plugins[ i ] = proto.plugins[ i ] || [];
287 proto.plugins[ i ].push( [ option, set[ i ] ] );
290 call: function( instance, name, args, allowDisconnected ) {
292 set = instance.plugins[ name ];
298 if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) ) {
302 for ( i = 0; i < set.length; i++ ) {
303 if ( instance.options[ set[ i ][ 0 ] ] ) {
304 set[ i ][ 1 ].apply( instance.element, args );
312 * jQuery UI Widget 1.11.4
313 * http://jqueryui.com
315 * Copyright jQuery Foundation and other contributors
316 * Released under the MIT license.
317 * http://jquery.org/license
319 * http://api.jqueryui.com/jQuery.widget/
324 widget_slice = Array.prototype.slice;
326 $.cleanData = (function( orig ) {
327 return function( elems ) {
329 for ( i = 0; (elem = elems[i]) != null; i++ ) {
332 // Only trigger remove when necessary to save time
333 events = $._data( elem, "events" );
334 if ( events && events.remove ) {
335 $( elem ).triggerHandler( "remove" );
338 // http://bugs.jquery.com/ticket/8235
345 $.widget = function( name, base, prototype ) {
346 var fullName, existingConstructor, constructor, basePrototype,
347 // proxiedPrototype allows the provided prototype to remain unmodified
348 // so that it can be used as a mixin for multiple widgets (#8876)
349 proxiedPrototype = {},
350 namespace = name.split( "." )[ 0 ];
352 name = name.split( "." )[ 1 ];
353 fullName = namespace + "-" + name;
360 // create selector for plugin
361 $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
362 return !!$.data( elem, fullName );
365 $[ namespace ] = $[ namespace ] || {};
366 existingConstructor = $[ namespace ][ name ];
367 constructor = $[ namespace ][ name ] = function( options, element ) {
368 // allow instantiation without "new" keyword
369 if ( !this._createWidget ) {
370 return new constructor( options, element );
373 // allow instantiation without initializing for simple inheritance
374 // must use "new" keyword (the code above always passes args)
375 if ( arguments.length ) {
376 this._createWidget( options, element );
379 // extend with the existing constructor to carry over any static properties
380 $.extend( constructor, existingConstructor, {
381 version: prototype.version,
382 // copy the object used to create the prototype in case we need to
383 // redefine the widget later
384 _proto: $.extend( {}, prototype ),
385 // track widgets that inherit from this widget in case this widget is
386 // redefined after a widget inherits from it
387 _childConstructors: []
390 basePrototype = new base();
391 // we need to make the options hash a property directly on the new instance
392 // otherwise we'll modify the options hash on the prototype that we're
394 basePrototype.options = $.widget.extend( {}, basePrototype.options );
395 $.each( prototype, function( prop, value ) {
396 if ( !$.isFunction( value ) ) {
397 proxiedPrototype[ prop ] = value;
400 proxiedPrototype[ prop ] = (function() {
401 var _super = function() {
402 return base.prototype[ prop ].apply( this, arguments );
404 _superApply = function( args ) {
405 return base.prototype[ prop ].apply( this, args );
408 var __super = this._super,
409 __superApply = this._superApply,
412 this._super = _super;
413 this._superApply = _superApply;
415 returnValue = value.apply( this, arguments );
417 this._super = __super;
418 this._superApply = __superApply;
424 constructor.prototype = $.widget.extend( basePrototype, {
425 // TODO: remove support for widgetEventPrefix
426 // always use the name + a colon as the prefix, e.g., draggable:start
427 // don't prefix for widgets that aren't DOM-based
428 widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name
429 }, proxiedPrototype, {
430 constructor: constructor,
431 namespace: namespace,
433 widgetFullName: fullName
436 // If this widget is being redefined then we need to find all widgets that
437 // are inheriting from it and redefine all of them so that they inherit from
438 // the new version of this widget. We're essentially trying to replace one
439 // level in the prototype chain.
440 if ( existingConstructor ) {
441 $.each( existingConstructor._childConstructors, function( i, child ) {
442 var childPrototype = child.prototype;
444 // redefine the child widget using the same prototype that was
445 // originally used, but inherit from the new version of the base
446 $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
448 // remove the list of existing child constructors from the old constructor
449 // so the old child constructors can be garbage collected
450 delete existingConstructor._childConstructors;
452 base._childConstructors.push( constructor );
455 $.widget.bridge( name, constructor );
460 $.widget.extend = function( target ) {
461 var input = widget_slice.call( arguments, 1 ),
463 inputLength = input.length,
466 for ( ; inputIndex < inputLength; inputIndex++ ) {
467 for ( key in input[ inputIndex ] ) {
468 value = input[ inputIndex ][ key ];
469 if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
471 if ( $.isPlainObject( value ) ) {
472 target[ key ] = $.isPlainObject( target[ key ] ) ?
473 $.widget.extend( {}, target[ key ], value ) :
474 // Don't extend strings, arrays, etc. with objects
475 $.widget.extend( {}, value );
476 // Copy everything else by reference
478 target[ key ] = value;
486 $.widget.bridge = function( name, object ) {
487 var fullName = object.prototype.widgetFullName || name;
488 $.fn[ name ] = function( options ) {
489 var isMethodCall = typeof options === "string",
490 args = widget_slice.call( arguments, 1 ),
493 if ( isMethodCall ) {
494 this.each(function() {
496 instance = $.data( this, fullName );
497 if ( options === "instance" ) {
498 returnValue = instance;
502 return $.error( "cannot call methods on " + name + " prior to initialization; " +
503 "attempted to call method '" + options + "'" );
505 if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
506 return $.error( "no such method '" + options + "' for " + name + " widget instance" );
508 methodValue = instance[ options ].apply( instance, args );
509 if ( methodValue !== instance && methodValue !== undefined ) {
510 returnValue = methodValue && methodValue.jquery ?
511 returnValue.pushStack( methodValue.get() ) :
518 // Allow multiple hashes to be passed on init
520 options = $.widget.extend.apply( null, [ options ].concat(args) );
523 this.each(function() {
524 var instance = $.data( this, fullName );
526 instance.option( options || {} );
527 if ( instance._init ) {
531 $.data( this, fullName, new object( options, this ) );
540 $.Widget = function( /* options, element */ ) {};
541 $.Widget._childConstructors = [];
543 $.Widget.prototype = {
544 widgetName: "widget",
545 widgetEventPrefix: "",
546 defaultElement: "<div>",
553 _createWidget: function( options, element ) {
554 element = $( element || this.defaultElement || this )[ 0 ];
555 this.element = $( element );
556 this.uuid = widget_uuid++;
557 this.eventNamespace = "." + this.widgetName + this.uuid;
560 this.hoverable = $();
561 this.focusable = $();
563 if ( element !== this ) {
564 $.data( element, this.widgetFullName, this );
565 this._on( true, this.element, {
566 remove: function( event ) {
567 if ( event.target === element ) {
572 this.document = $( element.style ?
573 // element within the document
574 element.ownerDocument :
575 // element is window or document
576 element.document || element );
577 this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
580 this.options = $.widget.extend( {},
582 this._getCreateOptions(),
586 this._trigger( "create", null, this._getCreateEventData() );
589 _getCreateOptions: $.noop,
590 _getCreateEventData: $.noop,
594 destroy: function() {
596 // we can probably remove the unbind calls in 2.0
597 // all event bindings should go through this._on()
599 .unbind( this.eventNamespace )
600 .removeData( this.widgetFullName )
601 // support: jquery <1.6.3
602 // http://bugs.jquery.com/ticket/9413
603 .removeData( $.camelCase( this.widgetFullName ) );
605 .unbind( this.eventNamespace )
606 .removeAttr( "aria-disabled" )
608 this.widgetFullName + "-disabled " +
609 "ui-state-disabled" );
611 // clean up events and states
612 this.bindings.unbind( this.eventNamespace );
613 this.hoverable.removeClass( "ui-state-hover" );
614 this.focusable.removeClass( "ui-state-focus" );
622 option: function( key, value ) {
628 if ( arguments.length === 0 ) {
629 // don't return a reference to the internal hash
630 return $.widget.extend( {}, this.options );
633 if ( typeof key === "string" ) {
634 // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
636 parts = key.split( "." );
638 if ( parts.length ) {
639 curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
640 for ( i = 0; i < parts.length - 1; i++ ) {
641 curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
642 curOption = curOption[ parts[ i ] ];
645 if ( arguments.length === 1 ) {
646 return curOption[ key ] === undefined ? null : curOption[ key ];
648 curOption[ key ] = value;
650 if ( arguments.length === 1 ) {
651 return this.options[ key ] === undefined ? null : this.options[ key ];
653 options[ key ] = value;
657 this._setOptions( options );
661 _setOptions: function( options ) {
664 for ( key in options ) {
665 this._setOption( key, options[ key ] );
670 _setOption: function( key, value ) {
671 this.options[ key ] = value;
673 if ( key === "disabled" ) {
675 .toggleClass( this.widgetFullName + "-disabled", !!value );
677 // If the widget is becoming disabled, then nothing is interactive
679 this.hoverable.removeClass( "ui-state-hover" );
680 this.focusable.removeClass( "ui-state-focus" );
688 return this._setOptions({ disabled: false });
690 disable: function() {
691 return this._setOptions({ disabled: true });
694 _on: function( suppressDisabledCheck, element, handlers ) {
698 // no suppressDisabledCheck flag, shuffle arguments
699 if ( typeof suppressDisabledCheck !== "boolean" ) {
701 element = suppressDisabledCheck;
702 suppressDisabledCheck = false;
705 // no element argument, shuffle and use this.element
708 element = this.element;
709 delegateElement = this.widget();
711 element = delegateElement = $( element );
712 this.bindings = this.bindings.add( element );
715 $.each( handlers, function( event, handler ) {
716 function handlerProxy() {
717 // allow widgets to customize the disabled handling
718 // - disabled as an array instead of boolean
719 // - disabled class as method for disabling individual parts
720 if ( !suppressDisabledCheck &&
721 ( instance.options.disabled === true ||
722 $( this ).hasClass( "ui-state-disabled" ) ) ) {
725 return ( typeof handler === "string" ? instance[ handler ] : handler )
726 .apply( instance, arguments );
729 // copy the guid so direct unbinding works
730 if ( typeof handler !== "string" ) {
731 handlerProxy.guid = handler.guid =
732 handler.guid || handlerProxy.guid || $.guid++;
735 var match = event.match( /^([\w:-]*)\s*(.*)$/ ),
736 eventName = match[1] + instance.eventNamespace,
739 delegateElement.delegate( selector, eventName, handlerProxy );
741 element.bind( eventName, handlerProxy );
746 _off: function( element, eventName ) {
747 eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) +
749 element.unbind( eventName ).undelegate( eventName );
751 // Clear the stack to avoid memory leaks (#10056)
752 this.bindings = $( this.bindings.not( element ).get() );
753 this.focusable = $( this.focusable.not( element ).get() );
754 this.hoverable = $( this.hoverable.not( element ).get() );
757 _delay: function( handler, delay ) {
758 function handlerProxy() {
759 return ( typeof handler === "string" ? instance[ handler ] : handler )
760 .apply( instance, arguments );
763 return setTimeout( handlerProxy, delay || 0 );
766 _hoverable: function( element ) {
767 this.hoverable = this.hoverable.add( element );
769 mouseenter: function( event ) {
770 $( event.currentTarget ).addClass( "ui-state-hover" );
772 mouseleave: function( event ) {
773 $( event.currentTarget ).removeClass( "ui-state-hover" );
778 _focusable: function( element ) {
779 this.focusable = this.focusable.add( element );
781 focusin: function( event ) {
782 $( event.currentTarget ).addClass( "ui-state-focus" );
784 focusout: function( event ) {
785 $( event.currentTarget ).removeClass( "ui-state-focus" );
790 _trigger: function( type, event, data ) {
792 callback = this.options[ type ];
795 event = $.Event( event );
796 event.type = ( type === this.widgetEventPrefix ?
798 this.widgetEventPrefix + type ).toLowerCase();
799 // the original event may come from any element
800 // so we need to reset the target on the new event
801 event.target = this.element[ 0 ];
803 // copy original event properties over to the new event
804 orig = event.originalEvent;
806 for ( prop in orig ) {
807 if ( !( prop in event ) ) {
808 event[ prop ] = orig[ prop ];
813 this.element.trigger( event, data );
814 return !( $.isFunction( callback ) &&
815 callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
816 event.isDefaultPrevented() );
820 $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
821 $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
822 if ( typeof options === "string" ) {
823 options = { effect: options };
826 effectName = !options ?
828 options === true || typeof options === "number" ?
830 options.effect || defaultEffect;
831 options = options || {};
832 if ( typeof options === "number" ) {
833 options = { duration: options };
835 hasOptions = !$.isEmptyObject( options );
836 options.complete = callback;
837 if ( options.delay ) {
838 element.delay( options.delay );
840 if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
841 element[ method ]( options );
842 } else if ( effectName !== method && element[ effectName ] ) {
843 element[ effectName ]( options.duration, options.easing, callback );
845 element.queue(function( next ) {
846 $( this )[ method ]();
848 callback.call( element[ 0 ] );
856 var widget = $.widget;
860 * jQuery UI Mouse 1.11.4
861 * http://jqueryui.com
863 * Copyright jQuery Foundation and other contributors
864 * Released under the MIT license.
865 * http://jquery.org/license
867 * http://api.jqueryui.com/mouse/
871 var mouseHandled = false;
872 $( document ).mouseup( function() {
873 mouseHandled = false;
876 var mouse = $.widget("ui.mouse", {
879 cancel: "input,textarea,button,select,option",
883 _mouseInit: function() {
887 .bind("mousedown." + this.widgetName, function(event) {
888 return that._mouseDown(event);
890 .bind("click." + this.widgetName, function(event) {
891 if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) {
892 $.removeData(event.target, that.widgetName + ".preventClickEvent");
893 event.stopImmediatePropagation();
898 this.started = false;
901 // TODO: make sure destroying one instance of mouse doesn't mess with
902 // other instances of mouse
903 _mouseDestroy: function() {
904 this.element.unbind("." + this.widgetName);
905 if ( this._mouseMoveDelegate ) {
907 .unbind("mousemove." + this.widgetName, this._mouseMoveDelegate)
908 .unbind("mouseup." + this.widgetName, this._mouseUpDelegate);
912 _mouseDown: function(event) {
913 // don't let more than one widget handle mouseStart
914 if ( mouseHandled ) {
918 this._mouseMoved = false;
920 // we may have missed mouseup (out of window)
921 (this._mouseStarted && this._mouseUp(event));
923 this._mouseDownEvent = event;
926 btnIsLeft = (event.which === 1),
927 // event.target.nodeName works around a bug in IE 8 with
928 // disabled inputs (#7620)
929 elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false);
930 if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
934 this.mouseDelayMet = !this.options.delay;
935 if (!this.mouseDelayMet) {
936 this._mouseDelayTimer = setTimeout(function() {
937 that.mouseDelayMet = true;
938 }, this.options.delay);
941 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
942 this._mouseStarted = (this._mouseStart(event) !== false);
943 if (!this._mouseStarted) {
944 event.preventDefault();
949 // Click event may never have fired (Gecko & Opera)
950 if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) {
951 $.removeData(event.target, this.widgetName + ".preventClickEvent");
954 // these delegates are required to keep context
955 this._mouseMoveDelegate = function(event) {
956 return that._mouseMove(event);
958 this._mouseUpDelegate = function(event) {
959 return that._mouseUp(event);
963 .bind( "mousemove." + this.widgetName, this._mouseMoveDelegate )
964 .bind( "mouseup." + this.widgetName, this._mouseUpDelegate );
966 event.preventDefault();
972 _mouseMove: function(event) {
973 // Only check for mouseups outside the document if you've moved inside the document
974 // at least once. This prevents the firing of mouseup in the case of IE<9, which will
975 // fire a mousemove event if content is placed under the cursor. See #7778
977 if ( this._mouseMoved ) {
978 // IE mouseup check - mouseup happened when mouse was out of window
979 if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) {
980 return this._mouseUp(event);
982 // Iframe mouseup check - mouseup occurred in another document
983 } else if ( !event.which ) {
984 return this._mouseUp( event );
988 if ( event.which || event.button ) {
989 this._mouseMoved = true;
992 if (this._mouseStarted) {
993 this._mouseDrag(event);
994 return event.preventDefault();
997 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
999 (this._mouseStart(this._mouseDownEvent, event) !== false);
1000 (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
1003 return !this._mouseStarted;
1006 _mouseUp: function(event) {
1008 .unbind( "mousemove." + this.widgetName, this._mouseMoveDelegate )
1009 .unbind( "mouseup." + this.widgetName, this._mouseUpDelegate );
1011 if (this._mouseStarted) {
1012 this._mouseStarted = false;
1014 if (event.target === this._mouseDownEvent.target) {
1015 $.data(event.target, this.widgetName + ".preventClickEvent", true);
1018 this._mouseStop(event);
1021 mouseHandled = false;
1025 _mouseDistanceMet: function(event) {
1027 Math.abs(this._mouseDownEvent.pageX - event.pageX),
1028 Math.abs(this._mouseDownEvent.pageY - event.pageY)
1029 ) >= this.options.distance
1033 _mouseDelayMet: function(/* event */) {
1034 return this.mouseDelayMet;
1037 // These are placeholder methods, to be overriden by extending plugin
1038 _mouseStart: function(/* event */) {},
1039 _mouseDrag: function(/* event */) {},
1040 _mouseStop: function(/* event */) {},
1041 _mouseCapture: function(/* event */) { return true; }
1046 * jQuery UI Position 1.11.4
1047 * http://jqueryui.com
1049 * Copyright jQuery Foundation and other contributors
1050 * Released under the MIT license.
1051 * http://jquery.org/license
1053 * http://api.jqueryui.com/position/
1060 var cachedScrollbarWidth, supportsOffsetFractions,
1064 rhorizontal = /left|center|right/,
1065 rvertical = /top|center|bottom/,
1066 roffset = /[\+\-]\d+(\.[\d]+)?%?/,
1069 _position = $.fn.position;
1071 function getOffsets( offsets, width, height ) {
1073 parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
1074 parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
1078 function parseCss( element, property ) {
1079 return parseInt( $.css( element, property ), 10 ) || 0;
1082 function getDimensions( elem ) {
1084 if ( raw.nodeType === 9 ) {
1086 width: elem.width(),
1087 height: elem.height(),
1088 offset: { top: 0, left: 0 }
1091 if ( $.isWindow( raw ) ) {
1093 width: elem.width(),
1094 height: elem.height(),
1095 offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
1098 if ( raw.preventDefault ) {
1102 offset: { top: raw.pageY, left: raw.pageX }
1106 width: elem.outerWidth(),
1107 height: elem.outerHeight(),
1108 offset: elem.offset()
1113 scrollbarWidth: function() {
1114 if ( cachedScrollbarWidth !== undefined ) {
1115 return cachedScrollbarWidth;
1118 div = $( "<div style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ),
1119 innerDiv = div.children()[0];
1121 $( "body" ).append( div );
1122 w1 = innerDiv.offsetWidth;
1123 div.css( "overflow", "scroll" );
1125 w2 = innerDiv.offsetWidth;
1128 w2 = div[0].clientWidth;
1133 return (cachedScrollbarWidth = w1 - w2);
1135 getScrollInfo: function( within ) {
1136 var overflowX = within.isWindow || within.isDocument ? "" :
1137 within.element.css( "overflow-x" ),
1138 overflowY = within.isWindow || within.isDocument ? "" :
1139 within.element.css( "overflow-y" ),
1140 hasOverflowX = overflowX === "scroll" ||
1141 ( overflowX === "auto" && within.width < within.element[0].scrollWidth ),
1142 hasOverflowY = overflowY === "scroll" ||
1143 ( overflowY === "auto" && within.height < within.element[0].scrollHeight );
1145 width: hasOverflowY ? $.position.scrollbarWidth() : 0,
1146 height: hasOverflowX ? $.position.scrollbarWidth() : 0
1149 getWithinInfo: function( element ) {
1150 var withinElement = $( element || window ),
1151 isWindow = $.isWindow( withinElement[0] ),
1152 isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9;
1154 element: withinElement,
1156 isDocument: isDocument,
1157 offset: withinElement.offset() || { left: 0, top: 0 },
1158 scrollLeft: withinElement.scrollLeft(),
1159 scrollTop: withinElement.scrollTop(),
1161 // support: jQuery 1.6.x
1162 // jQuery 1.6 doesn't support .outerWidth/Height() on documents or windows
1163 width: isWindow || isDocument ? withinElement.width() : withinElement.outerWidth(),
1164 height: isWindow || isDocument ? withinElement.height() : withinElement.outerHeight()
1169 $.fn.position = function( options ) {
1170 if ( !options || !options.of ) {
1171 return _position.apply( this, arguments );
1174 // make a copy, we don't want to modify arguments
1175 options = $.extend( {}, options );
1177 var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
1178 target = $( options.of ),
1179 within = $.position.getWithinInfo( options.within ),
1180 scrollInfo = $.position.getScrollInfo( within ),
1181 collision = ( options.collision || "flip" ).split( " " ),
1184 dimensions = getDimensions( target );
1185 if ( target[0].preventDefault ) {
1186 // force left top to allow flipping
1187 options.at = "left top";
1189 targetWidth = dimensions.width;
1190 targetHeight = dimensions.height;
1191 targetOffset = dimensions.offset;
1192 // clone to reuse original targetOffset later
1193 basePosition = $.extend( {}, targetOffset );
1195 // force my and at to have valid horizontal and vertical positions
1196 // if a value is missing or invalid, it will be converted to center
1197 $.each( [ "my", "at" ], function() {
1198 var pos = ( options[ this ] || "" ).split( " " ),
1202 if ( pos.length === 1) {
1203 pos = rhorizontal.test( pos[ 0 ] ) ?
1204 pos.concat( [ "center" ] ) :
1205 rvertical.test( pos[ 0 ] ) ?
1206 [ "center" ].concat( pos ) :
1207 [ "center", "center" ];
1209 pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
1210 pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
1212 // calculate offsets
1213 horizontalOffset = roffset.exec( pos[ 0 ] );
1214 verticalOffset = roffset.exec( pos[ 1 ] );
1216 horizontalOffset ? horizontalOffset[ 0 ] : 0,
1217 verticalOffset ? verticalOffset[ 0 ] : 0
1220 // reduce to just the positions without the offsets
1222 rposition.exec( pos[ 0 ] )[ 0 ],
1223 rposition.exec( pos[ 1 ] )[ 0 ]
1227 // normalize collision option
1228 if ( collision.length === 1 ) {
1229 collision[ 1 ] = collision[ 0 ];
1232 if ( options.at[ 0 ] === "right" ) {
1233 basePosition.left += targetWidth;
1234 } else if ( options.at[ 0 ] === "center" ) {
1235 basePosition.left += targetWidth / 2;
1238 if ( options.at[ 1 ] === "bottom" ) {
1239 basePosition.top += targetHeight;
1240 } else if ( options.at[ 1 ] === "center" ) {
1241 basePosition.top += targetHeight / 2;
1244 atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
1245 basePosition.left += atOffset[ 0 ];
1246 basePosition.top += atOffset[ 1 ];
1248 return this.each(function() {
1249 var collisionPosition, using,
1251 elemWidth = elem.outerWidth(),
1252 elemHeight = elem.outerHeight(),
1253 marginLeft = parseCss( this, "marginLeft" ),
1254 marginTop = parseCss( this, "marginTop" ),
1255 collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width,
1256 collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height,
1257 position = $.extend( {}, basePosition ),
1258 myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
1260 if ( options.my[ 0 ] === "right" ) {
1261 position.left -= elemWidth;
1262 } else if ( options.my[ 0 ] === "center" ) {
1263 position.left -= elemWidth / 2;
1266 if ( options.my[ 1 ] === "bottom" ) {
1267 position.top -= elemHeight;
1268 } else if ( options.my[ 1 ] === "center" ) {
1269 position.top -= elemHeight / 2;
1272 position.left += myOffset[ 0 ];
1273 position.top += myOffset[ 1 ];
1275 // if the browser doesn't support fractions, then round for consistent results
1276 if ( !supportsOffsetFractions ) {
1277 position.left = round( position.left );
1278 position.top = round( position.top );
1281 collisionPosition = {
1282 marginLeft: marginLeft,
1283 marginTop: marginTop
1286 $.each( [ "left", "top" ], function( i, dir ) {
1287 if ( $.ui.position[ collision[ i ] ] ) {
1288 $.ui.position[ collision[ i ] ][ dir ]( position, {
1289 targetWidth: targetWidth,
1290 targetHeight: targetHeight,
1291 elemWidth: elemWidth,
1292 elemHeight: elemHeight,
1293 collisionPosition: collisionPosition,
1294 collisionWidth: collisionWidth,
1295 collisionHeight: collisionHeight,
1296 offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
1305 if ( options.using ) {
1306 // adds feedback as second argument to using callback, if present
1307 using = function( props ) {
1308 var left = targetOffset.left - position.left,
1309 right = left + targetWidth - elemWidth,
1310 top = targetOffset.top - position.top,
1311 bottom = top + targetHeight - elemHeight,
1315 left: targetOffset.left,
1316 top: targetOffset.top,
1318 height: targetHeight
1322 left: position.left,
1327 horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
1328 vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
1330 if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
1331 feedback.horizontal = "center";
1333 if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
1334 feedback.vertical = "middle";
1336 if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
1337 feedback.important = "horizontal";
1339 feedback.important = "vertical";
1341 options.using.call( this, props, feedback );
1345 elem.offset( $.extend( position, { using: using } ) );
1351 left: function( position, data ) {
1352 var within = data.within,
1353 withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
1354 outerWidth = within.width,
1355 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
1356 overLeft = withinOffset - collisionPosLeft,
1357 overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
1360 // element is wider than within
1361 if ( data.collisionWidth > outerWidth ) {
1362 // element is initially over the left side of within
1363 if ( overLeft > 0 && overRight <= 0 ) {
1364 newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
1365 position.left += overLeft - newOverRight;
1366 // element is initially over right side of within
1367 } else if ( overRight > 0 && overLeft <= 0 ) {
1368 position.left = withinOffset;
1369 // element is initially over both left and right sides of within
1371 if ( overLeft > overRight ) {
1372 position.left = withinOffset + outerWidth - data.collisionWidth;
1374 position.left = withinOffset;
1377 // too far left -> align with left edge
1378 } else if ( overLeft > 0 ) {
1379 position.left += overLeft;
1380 // too far right -> align with right edge
1381 } else if ( overRight > 0 ) {
1382 position.left -= overRight;
1383 // adjust based on position and margin
1385 position.left = max( position.left - collisionPosLeft, position.left );
1388 top: function( position, data ) {
1389 var within = data.within,
1390 withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
1391 outerHeight = data.within.height,
1392 collisionPosTop = position.top - data.collisionPosition.marginTop,
1393 overTop = withinOffset - collisionPosTop,
1394 overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
1397 // element is taller than within
1398 if ( data.collisionHeight > outerHeight ) {
1399 // element is initially over the top of within
1400 if ( overTop > 0 && overBottom <= 0 ) {
1401 newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
1402 position.top += overTop - newOverBottom;
1403 // element is initially over bottom of within
1404 } else if ( overBottom > 0 && overTop <= 0 ) {
1405 position.top = withinOffset;
1406 // element is initially over both top and bottom of within
1408 if ( overTop > overBottom ) {
1409 position.top = withinOffset + outerHeight - data.collisionHeight;
1411 position.top = withinOffset;
1414 // too far up -> align with top
1415 } else if ( overTop > 0 ) {
1416 position.top += overTop;
1417 // too far down -> align with bottom edge
1418 } else if ( overBottom > 0 ) {
1419 position.top -= overBottom;
1420 // adjust based on position and margin
1422 position.top = max( position.top - collisionPosTop, position.top );
1427 left: function( position, data ) {
1428 var within = data.within,
1429 withinOffset = within.offset.left + within.scrollLeft,
1430 outerWidth = within.width,
1431 offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
1432 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
1433 overLeft = collisionPosLeft - offsetLeft,
1434 overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
1435 myOffset = data.my[ 0 ] === "left" ?
1437 data.my[ 0 ] === "right" ?
1440 atOffset = data.at[ 0 ] === "left" ?
1442 data.at[ 0 ] === "right" ?
1445 offset = -2 * data.offset[ 0 ],
1449 if ( overLeft < 0 ) {
1450 newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
1451 if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
1452 position.left += myOffset + atOffset + offset;
1454 } else if ( overRight > 0 ) {
1455 newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;
1456 if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
1457 position.left += myOffset + atOffset + offset;
1461 top: function( position, data ) {
1462 var within = data.within,
1463 withinOffset = within.offset.top + within.scrollTop,
1464 outerHeight = within.height,
1465 offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
1466 collisionPosTop = position.top - data.collisionPosition.marginTop,
1467 overTop = collisionPosTop - offsetTop,
1468 overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
1469 top = data.my[ 1 ] === "top",
1472 data.my[ 1 ] === "bottom" ?
1475 atOffset = data.at[ 1 ] === "top" ?
1477 data.at[ 1 ] === "bottom" ?
1478 -data.targetHeight :
1480 offset = -2 * data.offset[ 1 ],
1483 if ( overTop < 0 ) {
1484 newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
1485 if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) {
1486 position.top += myOffset + atOffset + offset;
1488 } else if ( overBottom > 0 ) {
1489 newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;
1490 if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) {
1491 position.top += myOffset + atOffset + offset;
1498 $.ui.position.flip.left.apply( this, arguments );
1499 $.ui.position.fit.left.apply( this, arguments );
1502 $.ui.position.flip.top.apply( this, arguments );
1503 $.ui.position.fit.top.apply( this, arguments );
1508 // fraction support test
1510 var testElement, testElementParent, testElementStyle, offsetLeft, i,
1511 body = document.getElementsByTagName( "body" )[ 0 ],
1512 div = document.createElement( "div" );
1514 //Create a "fake body" for testing based on method used in jQuery.support
1515 testElement = document.createElement( body ? "div" : "body" );
1516 testElementStyle = {
1517 visibility: "hidden",
1525 $.extend( testElementStyle, {
1526 position: "absolute",
1531 for ( i in testElementStyle ) {
1532 testElement.style[ i ] = testElementStyle[ i ];
1534 testElement.appendChild( div );
1535 testElementParent = body || document.documentElement;
1536 testElementParent.insertBefore( testElement, testElementParent.firstChild );
1538 div.style.cssText = "position: absolute; left: 10.7432222px;";
1540 offsetLeft = $( div ).offset().left;
1541 supportsOffsetFractions = offsetLeft > 10 && offsetLeft < 11;
1543 testElement.innerHTML = "";
1544 testElementParent.removeChild( testElement );
1549 var position = $.ui.position;
1553 * jQuery UI Draggable 1.11.4
1554 * http://jqueryui.com
1556 * Copyright jQuery Foundation and other contributors
1557 * Released under the MIT license.
1558 * http://jquery.org/license
1560 * http://api.jqueryui.com/draggable/
1564 $.widget("ui.draggable", $.ui.mouse, {
1566 widgetEventPrefix: "drag",
1571 connectToSortable: false,
1580 refreshPositions: false,
1582 revertDuration: 500,
1585 scrollSensitivity: 20,
1598 _create: function() {
1600 if ( this.options.helper === "original" ) {
1601 this._setPositionRelative();
1603 if (this.options.addClasses){
1604 this.element.addClass("ui-draggable");
1606 if (this.options.disabled){
1607 this.element.addClass("ui-draggable-disabled");
1609 this._setHandleClassName();
1614 _setOption: function( key, value ) {
1615 this._super( key, value );
1616 if ( key === "handle" ) {
1617 this._removeHandleClassName();
1618 this._setHandleClassName();
1622 _destroy: function() {
1623 if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) {
1624 this.destroyOnClear = true;
1627 this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" );
1628 this._removeHandleClassName();
1629 this._mouseDestroy();
1632 _mouseCapture: function(event) {
1633 var o = this.options;
1635 this._blurActiveElement( event );
1637 // among others, prevent a drag on a resizable-handle
1638 if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) {
1642 //Quit if we're not on a valid handle
1643 this.handle = this._getHandle(event);
1648 this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix );
1654 _blockFrames: function( selector ) {
1655 this.iframeBlocks = this.document.find( selector ).map(function() {
1656 var iframe = $( this );
1659 .css( "position", "absolute" )
1660 .appendTo( iframe.parent() )
1661 .outerWidth( iframe.outerWidth() )
1662 .outerHeight( iframe.outerHeight() )
1663 .offset( iframe.offset() )[ 0 ];
1667 _unblockFrames: function() {
1668 if ( this.iframeBlocks ) {
1669 this.iframeBlocks.remove();
1670 delete this.iframeBlocks;
1674 _blurActiveElement: function( event ) {
1675 var document = this.document[ 0 ];
1677 // Only need to blur if the event occurred on the draggable itself, see #10527
1678 if ( !this.handleElement.is( event.target ) ) {
1683 // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
1686 // Support: IE9, IE10
1687 // If the <body> is blurred, IE will switch windows, see #9520
1688 if ( document.activeElement && document.activeElement.nodeName.toLowerCase() !== "body" ) {
1690 // Blur any element that currently has focus, see #4261
1691 $( document.activeElement ).blur();
1693 } catch ( error ) {}
1696 _mouseStart: function(event) {
1698 var o = this.options;
1700 //Create and append the visible helper
1701 this.helper = this._createHelper(event);
1703 this.helper.addClass("ui-draggable-dragging");
1705 //Cache the helper size
1706 this._cacheHelperProportions();
1708 //If ddmanager is used for droppables, set the global draggable
1709 if ($.ui.ddmanager) {
1710 $.ui.ddmanager.current = this;
1714 * - Position generation -
1715 * This block generates everything position related - it's the core of draggables.
1718 //Cache the margins of the original element
1719 this._cacheMargins();
1721 //Store the helper's css position
1722 this.cssPosition = this.helper.css( "position" );
1723 this.scrollParent = this.helper.scrollParent( true );
1724 this.offsetParent = this.helper.offsetParent();
1725 this.hasFixedAncestor = this.helper.parents().filter(function() {
1726 return $( this ).css( "position" ) === "fixed";
1729 //The element's absolute position on the page minus margins
1730 this.positionAbs = this.element.offset();
1731 this._refreshOffsets( event );
1733 //Generate the original position
1734 this.originalPosition = this.position = this._generatePosition( event, false );
1735 this.originalPageX = event.pageX;
1736 this.originalPageY = event.pageY;
1738 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
1739 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
1741 //Set a containment if given in the options
1742 this._setContainment();
1744 //Trigger event + callbacks
1745 if (this._trigger("start", event) === false) {
1750 //Recache the helper size
1751 this._cacheHelperProportions();
1753 //Prepare the droppable offsets
1754 if ($.ui.ddmanager && !o.dropBehaviour) {
1755 $.ui.ddmanager.prepareOffsets(this, event);
1758 // Reset helper's right/bottom css if they're set and set explicit width/height instead
1759 // as this prevents resizing of elements with right/bottom set (see #7772)
1760 this._normalizeRightBottom();
1762 this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
1764 //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
1765 if ( $.ui.ddmanager ) {
1766 $.ui.ddmanager.dragStart(this, event);
1772 _refreshOffsets: function( event ) {
1774 top: this.positionAbs.top - this.margins.top,
1775 left: this.positionAbs.left - this.margins.left,
1777 parent: this._getParentOffset(),
1778 relative: this._getRelativeOffset()
1781 this.offset.click = {
1782 left: event.pageX - this.offset.left,
1783 top: event.pageY - this.offset.top
1787 _mouseDrag: function(event, noPropagation) {
1788 // reset any necessary cached properties (see #5009)
1789 if ( this.hasFixedAncestor ) {
1790 this.offset.parent = this._getParentOffset();
1793 //Compute the helpers position
1794 this.position = this._generatePosition( event, true );
1795 this.positionAbs = this._convertPositionTo("absolute");
1797 //Call plugins and callbacks and use the resulting position if something is returned
1798 if (!noPropagation) {
1799 var ui = this._uiHash();
1800 if (this._trigger("drag", event, ui) === false) {
1804 this.position = ui.position;
1807 this.helper[ 0 ].style.left = this.position.left + "px";
1808 this.helper[ 0 ].style.top = this.position.top + "px";
1810 if ($.ui.ddmanager) {
1811 $.ui.ddmanager.drag(this, event);
1817 _mouseStop: function(event) {
1819 //If we are using droppables, inform the manager about the drop
1822 if ($.ui.ddmanager && !this.options.dropBehaviour) {
1823 dropped = $.ui.ddmanager.drop(this, event);
1826 //if a drop comes from outside (a sortable)
1828 dropped = this.dropped;
1829 this.dropped = false;
1832 if ((this.options.revert === "invalid" && !dropped) || (this.options.revert === "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) {
1833 $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
1834 if (that._trigger("stop", event) !== false) {
1839 if (this._trigger("stop", event) !== false) {
1847 _mouseUp: function( event ) {
1848 this._unblockFrames();
1850 //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003)
1851 if ( $.ui.ddmanager ) {
1852 $.ui.ddmanager.dragStop(this, event);
1855 // Only need to focus if the event occurred on the draggable itself, see #10527
1856 if ( this.handleElement.is( event.target ) ) {
1857 // The interaction is over; whether or not the click resulted in a drag, focus the element
1858 this.element.focus();
1861 return $.ui.mouse.prototype._mouseUp.call(this, event);
1864 cancel: function() {
1866 if (this.helper.is(".ui-draggable-dragging")) {
1876 _getHandle: function(event) {
1877 return this.options.handle ?
1878 !!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
1882 _setHandleClassName: function() {
1883 this.handleElement = this.options.handle ?
1884 this.element.find( this.options.handle ) : this.element;
1885 this.handleElement.addClass( "ui-draggable-handle" );
1888 _removeHandleClassName: function() {
1889 this.handleElement.removeClass( "ui-draggable-handle" );
1892 _createHelper: function(event) {
1894 var o = this.options,
1895 helperIsFunction = $.isFunction( o.helper ),
1896 helper = helperIsFunction ?
1897 $( o.helper.apply( this.element[ 0 ], [ event ] ) ) :
1898 ( o.helper === "clone" ?
1899 this.element.clone().removeAttr( "id" ) :
1902 if (!helper.parents("body").length) {
1903 helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo));
1906 // http://bugs.jqueryui.com/ticket/9446
1907 // a helper function can return the original element
1908 // which wouldn't have been set to relative in _create
1909 if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) {
1910 this._setPositionRelative();
1913 if (helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) {
1914 helper.css("position", "absolute");
1921 _setPositionRelative: function() {
1922 if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) {
1923 this.element[ 0 ].style.position = "relative";
1927 _adjustOffsetFromHelper: function(obj) {
1928 if (typeof obj === "string") {
1929 obj = obj.split(" ");
1931 if ($.isArray(obj)) {
1932 obj = { left: +obj[0], top: +obj[1] || 0 };
1934 if ("left" in obj) {
1935 this.offset.click.left = obj.left + this.margins.left;
1937 if ("right" in obj) {
1938 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
1941 this.offset.click.top = obj.top + this.margins.top;
1943 if ("bottom" in obj) {
1944 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
1948 _isRootNode: function( element ) {
1949 return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ];
1952 _getParentOffset: function() {
1954 //Get the offsetParent and cache its position
1955 var po = this.offsetParent.offset(),
1956 document = this.document[ 0 ];
1958 // This is a special case where we need to modify a offset calculated on start, since the following happened:
1959 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
1960 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
1961 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
1962 if (this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
1963 po.left += this.scrollParent.scrollLeft();
1964 po.top += this.scrollParent.scrollTop();
1967 if ( this._isRootNode( this.offsetParent[ 0 ] ) ) {
1968 po = { top: 0, left: 0 };
1972 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"), 10) || 0),
1973 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"), 10) || 0)
1978 _getRelativeOffset: function() {
1979 if ( this.cssPosition !== "relative" ) {
1980 return { top: 0, left: 0 };
1983 var p = this.element.position(),
1984 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
1987 top: p.top - ( parseInt(this.helper.css( "top" ), 10) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ),
1988 left: p.left - ( parseInt(this.helper.css( "left" ), 10) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 )
1993 _cacheMargins: function() {
1995 left: (parseInt(this.element.css("marginLeft"), 10) || 0),
1996 top: (parseInt(this.element.css("marginTop"), 10) || 0),
1997 right: (parseInt(this.element.css("marginRight"), 10) || 0),
1998 bottom: (parseInt(this.element.css("marginBottom"), 10) || 0)
2002 _cacheHelperProportions: function() {
2003 this.helperProportions = {
2004 width: this.helper.outerWidth(),
2005 height: this.helper.outerHeight()
2009 _setContainment: function() {
2011 var isUserScrollable, c, ce,
2013 document = this.document[ 0 ];
2015 this.relativeContainer = null;
2017 if ( !o.containment ) {
2018 this.containment = null;
2022 if ( o.containment === "window" ) {
2023 this.containment = [
2024 $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
2025 $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
2026 $( window ).scrollLeft() + $( window ).width() - this.helperProportions.width - this.margins.left,
2027 $( window ).scrollTop() + ( $( window ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
2032 if ( o.containment === "document") {
2033 this.containment = [
2036 $( document ).width() - this.helperProportions.width - this.margins.left,
2037 ( $( document ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
2042 if ( o.containment.constructor === Array ) {
2043 this.containment = o.containment;
2047 if ( o.containment === "parent" ) {
2048 o.containment = this.helper[ 0 ].parentNode;
2051 c = $( o.containment );
2058 isUserScrollable = /(scroll|auto)/.test( c.css( "overflow" ) );
2060 this.containment = [
2061 ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
2062 ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ),
2063 ( isUserScrollable ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
2064 ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) -
2065 ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) -
2066 this.helperProportions.width -
2069 ( isUserScrollable ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
2070 ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) -
2071 ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) -
2072 this.helperProportions.height -
2076 this.relativeContainer = c;
2079 _convertPositionTo: function(d, pos) {
2082 pos = this.position;
2085 var mod = d === "absolute" ? 1 : -1,
2086 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
2090 pos.top + // The absolute mouse position
2091 this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
2092 this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
2093 ( ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod)
2096 pos.left + // The absolute mouse position
2097 this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
2098 this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
2099 ( ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod)
2105 _generatePosition: function( event, constrainPosition ) {
2107 var containment, co, top, left,
2109 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ),
2110 pageX = event.pageX,
2111 pageY = event.pageY;
2114 if ( !scrollIsRootNode || !this.offset.scroll ) {
2115 this.offset.scroll = {
2116 top: this.scrollParent.scrollTop(),
2117 left: this.scrollParent.scrollLeft()
2122 * - Position constraining -
2123 * Constrain the position to a mix of grid, containment.
2126 // If we are not dragging yet, we won't check for options
2127 if ( constrainPosition ) {
2128 if ( this.containment ) {
2129 if ( this.relativeContainer ){
2130 co = this.relativeContainer.offset();
2132 this.containment[ 0 ] + co.left,
2133 this.containment[ 1 ] + co.top,
2134 this.containment[ 2 ] + co.left,
2135 this.containment[ 3 ] + co.top
2138 containment = this.containment;
2141 if (event.pageX - this.offset.click.left < containment[0]) {
2142 pageX = containment[0] + this.offset.click.left;
2144 if (event.pageY - this.offset.click.top < containment[1]) {
2145 pageY = containment[1] + this.offset.click.top;
2147 if (event.pageX - this.offset.click.left > containment[2]) {
2148 pageX = containment[2] + this.offset.click.left;
2150 if (event.pageY - this.offset.click.top > containment[3]) {
2151 pageY = containment[3] + this.offset.click.top;
2156 //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950)
2157 top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY;
2158 pageY = containment ? ((top - this.offset.click.top >= containment[1] || top - this.offset.click.top > containment[3]) ? top : ((top - this.offset.click.top >= containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
2160 left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX;
2161 pageX = containment ? ((left - this.offset.click.left >= containment[0] || left - this.offset.click.left > containment[2]) ? left : ((left - this.offset.click.left >= containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
2164 if ( o.axis === "y" ) {
2165 pageX = this.originalPageX;
2168 if ( o.axis === "x" ) {
2169 pageY = this.originalPageY;
2175 pageY - // The absolute mouse position
2176 this.offset.click.top - // Click offset (relative to the element)
2177 this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
2178 this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
2179 ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) )
2182 pageX - // The absolute mouse position
2183 this.offset.click.left - // Click offset (relative to the element)
2184 this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
2185 this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
2186 ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) )
2192 _clear: function() {
2193 this.helper.removeClass("ui-draggable-dragging");
2194 if (this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) {
2195 this.helper.remove();
2198 this.cancelHelperRemoval = false;
2199 if ( this.destroyOnClear ) {
2204 _normalizeRightBottom: function() {
2205 if ( this.options.axis !== "y" && this.helper.css( "right" ) !== "auto" ) {
2206 this.helper.width( this.helper.width() );
2207 this.helper.css( "right", "auto" );
2209 if ( this.options.axis !== "x" && this.helper.css( "bottom" ) !== "auto" ) {
2210 this.helper.height( this.helper.height() );
2211 this.helper.css( "bottom", "auto" );
2215 // From now on bulk stuff - mainly helpers
2217 _trigger: function( type, event, ui ) {
2218 ui = ui || this._uiHash();
2219 $.ui.plugin.call( this, type, [ event, ui, this ], true );
2221 // Absolute position and offset (see #6884 ) have to be recalculated after plugins
2222 if ( /^(drag|start|stop)/.test( type ) ) {
2223 this.positionAbs = this._convertPositionTo( "absolute" );
2224 ui.offset = this.positionAbs;
2226 return $.Widget.prototype._trigger.call( this, type, event, ui );
2231 _uiHash: function() {
2233 helper: this.helper,
2234 position: this.position,
2235 originalPosition: this.originalPosition,
2236 offset: this.positionAbs
2242 $.ui.plugin.add( "draggable", "connectToSortable", {
2243 start: function( event, ui, draggable ) {
2244 var uiSortable = $.extend( {}, ui, {
2245 item: draggable.element
2248 draggable.sortables = [];
2249 $( draggable.options.connectToSortable ).each(function() {
2250 var sortable = $( this ).sortable( "instance" );
2252 if ( sortable && !sortable.options.disabled ) {
2253 draggable.sortables.push( sortable );
2255 // refreshPositions is called at drag start to refresh the containerCache
2256 // which is used in drag. This ensures it's initialized and synchronized
2257 // with any changes that might have happened on the page since initialization.
2258 sortable.refreshPositions();
2259 sortable._trigger("activate", event, uiSortable);
2263 stop: function( event, ui, draggable ) {
2264 var uiSortable = $.extend( {}, ui, {
2265 item: draggable.element
2268 draggable.cancelHelperRemoval = false;
2270 $.each( draggable.sortables, function() {
2271 var sortable = this;
2273 if ( sortable.isOver ) {
2274 sortable.isOver = 0;
2276 // Allow this sortable to handle removing the helper
2277 draggable.cancelHelperRemoval = true;
2278 sortable.cancelHelperRemoval = false;
2280 // Use _storedCSS To restore properties in the sortable,
2281 // as this also handles revert (#9675) since the draggable
2282 // may have modified them in unexpected ways (#8809)
2283 sortable._storedCSS = {
2284 position: sortable.placeholder.css( "position" ),
2285 top: sortable.placeholder.css( "top" ),
2286 left: sortable.placeholder.css( "left" )
2289 sortable._mouseStop(event);
2291 // Once drag has ended, the sortable should return to using
2292 // its original helper, not the shared helper from draggable
2293 sortable.options.helper = sortable.options._helper;
2295 // Prevent this Sortable from removing the helper.
2296 // However, don't set the draggable to remove the helper
2297 // either as another connected Sortable may yet handle the removal.
2298 sortable.cancelHelperRemoval = true;
2300 sortable._trigger( "deactivate", event, uiSortable );
2304 drag: function( event, ui, draggable ) {
2305 $.each( draggable.sortables, function() {
2306 var innermostIntersecting = false,
2309 // Copy over variables that sortable's _intersectsWith uses
2310 sortable.positionAbs = draggable.positionAbs;
2311 sortable.helperProportions = draggable.helperProportions;
2312 sortable.offset.click = draggable.offset.click;
2314 if ( sortable._intersectsWith( sortable.containerCache ) ) {
2315 innermostIntersecting = true;
2317 $.each( draggable.sortables, function() {
2318 // Copy over variables that sortable's _intersectsWith uses
2319 this.positionAbs = draggable.positionAbs;
2320 this.helperProportions = draggable.helperProportions;
2321 this.offset.click = draggable.offset.click;
2323 if ( this !== sortable &&
2324 this._intersectsWith( this.containerCache ) &&
2325 $.contains( sortable.element[ 0 ], this.element[ 0 ] ) ) {
2326 innermostIntersecting = false;
2329 return innermostIntersecting;
2333 if ( innermostIntersecting ) {
2334 // If it intersects, we use a little isOver variable and set it once,
2335 // so that the move-in stuff gets fired only once.
2336 if ( !sortable.isOver ) {
2337 sortable.isOver = 1;
2339 // Store draggable's parent in case we need to reappend to it later.
2340 draggable._parent = ui.helper.parent();
2342 sortable.currentItem = ui.helper
2343 .appendTo( sortable.element )
2344 .data( "ui-sortable-item", true );
2346 // Store helper option to later restore it
2347 sortable.options._helper = sortable.options.helper;
2349 sortable.options.helper = function() {
2350 return ui.helper[ 0 ];
2353 // Fire the start events of the sortable with our passed browser event,
2354 // and our own helper (so it doesn't create a new one)
2355 event.target = sortable.currentItem[ 0 ];
2356 sortable._mouseCapture( event, true );
2357 sortable._mouseStart( event, true, true );
2359 // Because the browser event is way off the new appended portlet,
2360 // modify necessary variables to reflect the changes
2361 sortable.offset.click.top = draggable.offset.click.top;
2362 sortable.offset.click.left = draggable.offset.click.left;
2363 sortable.offset.parent.left -= draggable.offset.parent.left -
2364 sortable.offset.parent.left;
2365 sortable.offset.parent.top -= draggable.offset.parent.top -
2366 sortable.offset.parent.top;
2368 draggable._trigger( "toSortable", event );
2370 // Inform draggable that the helper is in a valid drop zone,
2371 // used solely in the revert option to handle "valid/invalid".
2372 draggable.dropped = sortable.element;
2374 // Need to refreshPositions of all sortables in the case that
2375 // adding to one sortable changes the location of the other sortables (#9675)
2376 $.each( draggable.sortables, function() {
2377 this.refreshPositions();
2380 // hack so receive/update callbacks work (mostly)
2381 draggable.currentItem = draggable.element;
2382 sortable.fromOutside = draggable;
2385 if ( sortable.currentItem ) {
2386 sortable._mouseDrag( event );
2387 // Copy the sortable's position because the draggable's can potentially reflect
2388 // a relative position, while sortable is always absolute, which the dragged
2389 // element has now become. (#8809)
2390 ui.position = sortable.position;
2393 // If it doesn't intersect with the sortable, and it intersected before,
2394 // we fake the drag stop of the sortable, but make sure it doesn't remove
2395 // the helper by using cancelHelperRemoval.
2396 if ( sortable.isOver ) {
2398 sortable.isOver = 0;
2399 sortable.cancelHelperRemoval = true;
2401 // Calling sortable's mouseStop would trigger a revert,
2402 // so revert must be temporarily false until after mouseStop is called.
2403 sortable.options._revert = sortable.options.revert;
2404 sortable.options.revert = false;
2406 sortable._trigger( "out", event, sortable._uiHash( sortable ) );
2407 sortable._mouseStop( event, true );
2409 // restore sortable behaviors that were modfied
2410 // when the draggable entered the sortable area (#9481)
2411 sortable.options.revert = sortable.options._revert;
2412 sortable.options.helper = sortable.options._helper;
2414 if ( sortable.placeholder ) {
2415 sortable.placeholder.remove();
2418 // Restore and recalculate the draggable's offset considering the sortable
2419 // may have modified them in unexpected ways. (#8809, #10669)
2420 ui.helper.appendTo( draggable._parent );
2421 draggable._refreshOffsets( event );
2422 ui.position = draggable._generatePosition( event, true );
2424 draggable._trigger( "fromSortable", event );
2426 // Inform draggable that the helper is no longer in a valid drop zone
2427 draggable.dropped = false;
2429 // Need to refreshPositions of all sortables just in case removing
2430 // from one sortable changes the location of other sortables (#9675)
2431 $.each( draggable.sortables, function() {
2432 this.refreshPositions();
2440 $.ui.plugin.add("draggable", "cursor", {
2441 start: function( event, ui, instance ) {
2442 var t = $( "body" ),
2443 o = instance.options;
2445 if (t.css("cursor")) {
2446 o._cursor = t.css("cursor");
2448 t.css("cursor", o.cursor);
2450 stop: function( event, ui, instance ) {
2451 var o = instance.options;
2453 $("body").css("cursor", o._cursor);
2458 $.ui.plugin.add("draggable", "opacity", {
2459 start: function( event, ui, instance ) {
2460 var t = $( ui.helper ),
2461 o = instance.options;
2462 if (t.css("opacity")) {
2463 o._opacity = t.css("opacity");
2465 t.css("opacity", o.opacity);
2467 stop: function( event, ui, instance ) {
2468 var o = instance.options;
2470 $(ui.helper).css("opacity", o._opacity);
2475 $.ui.plugin.add("draggable", "scroll", {
2476 start: function( event, ui, i ) {
2477 if ( !i.scrollParentNotHidden ) {
2478 i.scrollParentNotHidden = i.helper.scrollParent( false );
2481 if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] && i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) {
2482 i.overflowOffset = i.scrollParentNotHidden.offset();
2485 drag: function( event, ui, i ) {
2489 scrollParent = i.scrollParentNotHidden[ 0 ],
2490 document = i.document[ 0 ];
2492 if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) {
2493 if ( !o.axis || o.axis !== "x" ) {
2494 if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY < o.scrollSensitivity ) {
2495 scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed;
2496 } else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) {
2497 scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed;
2501 if ( !o.axis || o.axis !== "y" ) {
2502 if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX < o.scrollSensitivity ) {
2503 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed;
2504 } else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) {
2505 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed;
2511 if (!o.axis || o.axis !== "x") {
2512 if (event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
2513 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
2514 } else if ($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
2515 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
2519 if (!o.axis || o.axis !== "y") {
2520 if (event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
2521 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
2522 } else if ($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
2523 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
2529 if (scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
2530 $.ui.ddmanager.prepareOffsets(i, event);
2536 $.ui.plugin.add("draggable", "snap", {
2537 start: function( event, ui, i ) {
2541 i.snapElements = [];
2543 $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() {
2546 if (this !== i.element[0]) {
2547 i.snapElements.push({
2549 width: $t.outerWidth(), height: $t.outerHeight(),
2550 top: $o.top, left: $o.left
2556 drag: function( event, ui, inst ) {
2558 var ts, bs, ls, rs, l, r, t, b, i, first,
2560 d = o.snapTolerance,
2561 x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
2562 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
2564 for (i = inst.snapElements.length - 1; i >= 0; i--){
2566 l = inst.snapElements[i].left - inst.margins.left;
2567 r = l + inst.snapElements[i].width;
2568 t = inst.snapElements[i].top - inst.margins.top;
2569 b = t + inst.snapElements[i].height;
2571 if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || !$.contains( inst.snapElements[ i ].item.ownerDocument, inst.snapElements[ i ].item ) ) {
2572 if (inst.snapElements[i].snapping) {
2573 (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
2575 inst.snapElements[i].snapping = false;
2579 if (o.snapMode !== "inner") {
2580 ts = Math.abs(t - y2) <= d;
2581 bs = Math.abs(b - y1) <= d;
2582 ls = Math.abs(l - x2) <= d;
2583 rs = Math.abs(r - x1) <= d;
2585 ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top;
2588 ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top;
2591 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left;
2594 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left;
2598 first = (ts || bs || ls || rs);
2600 if (o.snapMode !== "outer") {
2601 ts = Math.abs(t - y1) <= d;
2602 bs = Math.abs(b - y2) <= d;
2603 ls = Math.abs(l - x1) <= d;
2604 rs = Math.abs(r - x2) <= d;
2606 ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top;
2609 ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top;
2612 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left;
2615 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left;
2619 if (!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) {
2620 (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
2622 inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
2629 $.ui.plugin.add("draggable", "stack", {
2630 start: function( event, ui, instance ) {
2632 o = instance.options,
2633 group = $.makeArray($(o.stack)).sort(function(a, b) {
2634 return (parseInt($(a).css("zIndex"), 10) || 0) - (parseInt($(b).css("zIndex"), 10) || 0);
2637 if (!group.length) { return; }
2639 min = parseInt($(group[0]).css("zIndex"), 10) || 0;
2640 $(group).each(function(i) {
2641 $(this).css("zIndex", min + i);
2643 this.css("zIndex", (min + group.length));
2647 $.ui.plugin.add("draggable", "zIndex", {
2648 start: function( event, ui, instance ) {
2649 var t = $( ui.helper ),
2650 o = instance.options;
2652 if (t.css("zIndex")) {
2653 o._zIndex = t.css("zIndex");
2655 t.css("zIndex", o.zIndex);
2657 stop: function( event, ui, instance ) {
2658 var o = instance.options;
2661 $(ui.helper).css("zIndex", o._zIndex);
2666 var draggable = $.ui.draggable;
2670 * jQuery UI Droppable 1.11.4
2671 * http://jqueryui.com
2673 * Copyright jQuery Foundation and other contributors
2674 * Released under the MIT license.
2675 * http://jquery.org/license
2677 * http://api.jqueryui.com/droppable/
2681 $.widget( "ui.droppable", {
2683 widgetEventPrefix: "drop",
2691 tolerance: "intersect",
2700 _create: function() {
2706 this.isover = false;
2709 this.accept = $.isFunction( accept ) ? accept : function( d ) {
2710 return d.is( accept );
2713 this.proportions = function( /* valueToWrite */ ) {
2714 if ( arguments.length ) {
2715 // Store the droppable's proportions
2716 proportions = arguments[ 0 ];
2718 // Retrieve or derive the droppable's proportions
2719 return proportions ?
2722 width: this.element[ 0 ].offsetWidth,
2723 height: this.element[ 0 ].offsetHeight
2728 this._addToManager( o.scope );
2730 o.addClasses && this.element.addClass( "ui-droppable" );
2734 _addToManager: function( scope ) {
2735 // Add the reference and positions to the manager
2736 $.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || [];
2737 $.ui.ddmanager.droppables[ scope ].push( this );
2740 _splice: function( drop ) {
2742 for ( ; i < drop.length; i++ ) {
2743 if ( drop[ i ] === this ) {
2744 drop.splice( i, 1 );
2749 _destroy: function() {
2750 var drop = $.ui.ddmanager.droppables[ this.options.scope ];
2752 this._splice( drop );
2754 this.element.removeClass( "ui-droppable ui-droppable-disabled" );
2757 _setOption: function( key, value ) {
2759 if ( key === "accept" ) {
2760 this.accept = $.isFunction( value ) ? value : function( d ) {
2761 return d.is( value );
2763 } else if ( key === "scope" ) {
2764 var drop = $.ui.ddmanager.droppables[ this.options.scope ];
2766 this._splice( drop );
2767 this._addToManager( value );
2770 this._super( key, value );
2773 _activate: function( event ) {
2774 var draggable = $.ui.ddmanager.current;
2775 if ( this.options.activeClass ) {
2776 this.element.addClass( this.options.activeClass );
2779 this._trigger( "activate", event, this.ui( draggable ) );
2783 _deactivate: function( event ) {
2784 var draggable = $.ui.ddmanager.current;
2785 if ( this.options.activeClass ) {
2786 this.element.removeClass( this.options.activeClass );
2789 this._trigger( "deactivate", event, this.ui( draggable ) );
2793 _over: function( event ) {
2795 var draggable = $.ui.ddmanager.current;
2797 // Bail if draggable and droppable are same element
2798 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
2802 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
2803 if ( this.options.hoverClass ) {
2804 this.element.addClass( this.options.hoverClass );
2806 this._trigger( "over", event, this.ui( draggable ) );
2811 _out: function( event ) {
2813 var draggable = $.ui.ddmanager.current;
2815 // Bail if draggable and droppable are same element
2816 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
2820 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
2821 if ( this.options.hoverClass ) {
2822 this.element.removeClass( this.options.hoverClass );
2824 this._trigger( "out", event, this.ui( draggable ) );
2829 _drop: function( event, custom ) {
2831 var draggable = custom || $.ui.ddmanager.current,
2832 childrenIntersection = false;
2834 // Bail if draggable and droppable are same element
2835 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
2839 this.element.find( ":data(ui-droppable)" ).not( ".ui-draggable-dragging" ).each(function() {
2840 var inst = $( this ).droppable( "instance" );
2842 inst.options.greedy &&
2843 !inst.options.disabled &&
2844 inst.options.scope === draggable.options.scope &&
2845 inst.accept.call( inst.element[ 0 ], ( draggable.currentItem || draggable.element ) ) &&
2846 $.ui.intersect( draggable, $.extend( inst, { offset: inst.element.offset() } ), inst.options.tolerance, event )
2847 ) { childrenIntersection = true; return false; }
2849 if ( childrenIntersection ) {
2853 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
2854 if ( this.options.activeClass ) {
2855 this.element.removeClass( this.options.activeClass );
2857 if ( this.options.hoverClass ) {
2858 this.element.removeClass( this.options.hoverClass );
2860 this._trigger( "drop", event, this.ui( draggable ) );
2861 return this.element;
2870 draggable: ( c.currentItem || c.element ),
2872 position: c.position,
2873 offset: c.positionAbs
2879 $.ui.intersect = (function() {
2880 function isOverAxis( x, reference, size ) {
2881 return ( x >= reference ) && ( x < ( reference + size ) );
2884 return function( draggable, droppable, toleranceMode, event ) {
2886 if ( !droppable.offset ) {
2890 var x1 = ( draggable.positionAbs || draggable.position.absolute ).left + draggable.margins.left,
2891 y1 = ( draggable.positionAbs || draggable.position.absolute ).top + draggable.margins.top,
2892 x2 = x1 + draggable.helperProportions.width,
2893 y2 = y1 + draggable.helperProportions.height,
2894 l = droppable.offset.left,
2895 t = droppable.offset.top,
2896 r = l + droppable.proportions().width,
2897 b = t + droppable.proportions().height;
2899 switch ( toleranceMode ) {
2901 return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b );
2903 return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half
2904 x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half
2905 t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half
2906 y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half
2908 return isOverAxis( event.pageY, t, droppable.proportions().height ) && isOverAxis( event.pageX, l, droppable.proportions().width );
2911 ( y1 >= t && y1 <= b ) || // Top edge touching
2912 ( y2 >= t && y2 <= b ) || // Bottom edge touching
2913 ( y1 < t && y2 > b ) // Surrounded vertically
2915 ( x1 >= l && x1 <= r ) || // Left edge touching
2916 ( x2 >= l && x2 <= r ) || // Right edge touching
2917 ( x1 < l && x2 > r ) // Surrounded horizontally
2926 This manager tracks offsets of draggables and droppables
2930 droppables: { "default": [] },
2931 prepareOffsets: function( t, event ) {
2934 m = $.ui.ddmanager.droppables[ t.options.scope ] || [],
2935 type = event ? event.type : null, // workaround for #2317
2936 list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack();
2938 droppablesLoop: for ( i = 0; i < m.length; i++ ) {
2940 // No disabled and non-accepted
2941 if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ], ( t.currentItem || t.element ) ) ) ) {
2945 // Filter out elements in the current dragged item
2946 for ( j = 0; j < list.length; j++ ) {
2947 if ( list[ j ] === m[ i ].element[ 0 ] ) {
2948 m[ i ].proportions().height = 0;
2949 continue droppablesLoop;
2953 m[ i ].visible = m[ i ].element.css( "display" ) !== "none";
2954 if ( !m[ i ].visible ) {
2958 // Activate the droppable if used directly from draggables
2959 if ( type === "mousedown" ) {
2960 m[ i ]._activate.call( m[ i ], event );
2963 m[ i ].offset = m[ i ].element.offset();
2964 m[ i ].proportions({ width: m[ i ].element[ 0 ].offsetWidth, height: m[ i ].element[ 0 ].offsetHeight });
2969 drop: function( draggable, event ) {
2971 var dropped = false;
2972 // Create a copy of the droppables in case the list changes during the drop (#9116)
2973 $.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() {
2975 if ( !this.options ) {
2978 if ( !this.options.disabled && this.visible && $.ui.intersect( draggable, this, this.options.tolerance, event ) ) {
2979 dropped = this._drop.call( this, event ) || dropped;
2982 if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
2984 this.isover = false;
2985 this._deactivate.call( this, event );
2992 dragStart: function( draggable, event ) {
2993 // Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003)
2994 draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() {
2995 if ( !draggable.options.refreshPositions ) {
2996 $.ui.ddmanager.prepareOffsets( draggable, event );
3000 drag: function( draggable, event ) {
3002 // If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
3003 if ( draggable.options.refreshPositions ) {
3004 $.ui.ddmanager.prepareOffsets( draggable, event );
3007 // Run through all droppables and check their positions based on specific tolerance options
3008 $.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() {
3010 if ( this.options.disabled || this.greedyChild || !this.visible ) {
3014 var parentInstance, scope, parent,
3015 intersects = $.ui.intersect( draggable, this, this.options.tolerance, event ),
3016 c = !intersects && this.isover ? "isout" : ( intersects && !this.isover ? "isover" : null );
3021 if ( this.options.greedy ) {
3022 // find droppable parents with same scope
3023 scope = this.options.scope;
3024 parent = this.element.parents( ":data(ui-droppable)" ).filter(function() {
3025 return $( this ).droppable( "instance" ).options.scope === scope;
3028 if ( parent.length ) {
3029 parentInstance = $( parent[ 0 ] ).droppable( "instance" );
3030 parentInstance.greedyChild = ( c === "isover" );
3034 // we just moved into a greedy child
3035 if ( parentInstance && c === "isover" ) {
3036 parentInstance.isover = false;
3037 parentInstance.isout = true;
3038 parentInstance._out.call( parentInstance, event );
3042 this[c === "isout" ? "isover" : "isout"] = false;
3043 this[c === "isover" ? "_over" : "_out"].call( this, event );
3045 // we just moved out of a greedy child
3046 if ( parentInstance && c === "isout" ) {
3047 parentInstance.isout = false;
3048 parentInstance.isover = true;
3049 parentInstance._over.call( parentInstance, event );
3054 dragStop: function( draggable, event ) {
3055 draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" );
3056 // Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003)
3057 if ( !draggable.options.refreshPositions ) {
3058 $.ui.ddmanager.prepareOffsets( draggable, event );
3063 var droppable = $.ui.droppable;
3067 * jQuery UI Sortable 1.11.4
3068 * http://jqueryui.com
3070 * Copyright jQuery Foundation and other contributors
3071 * Released under the MIT license.
3072 * http://jquery.org/license
3074 * http://api.jqueryui.com/sortable/
3078 var sortable = $.widget("ui.sortable", $.ui.mouse, {
3080 widgetEventPrefix: "sort",
3090 forcePlaceholderSize: false,
3091 forceHelperSize: false,
3100 scrollSensitivity: 20,
3103 tolerance: "intersect",
3121 _isOverAxis: function( x, reference, size ) {
3122 return ( x >= reference ) && ( x < ( reference + size ) );
3125 _isFloating: function( item ) {
3126 return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display"));
3129 _create: function() {
3130 this.containerCache = {};
3131 this.element.addClass("ui-sortable");
3136 //Let's determine the parent's offset
3137 this.offset = this.element.offset();
3139 //Initialize mouse events for interaction
3142 this._setHandleClassName();
3149 _setOption: function( key, value ) {
3150 this._super( key, value );
3152 if ( key === "handle" ) {
3153 this._setHandleClassName();
3157 _setHandleClassName: function() {
3158 this.element.find( ".ui-sortable-handle" ).removeClass( "ui-sortable-handle" );
3159 $.each( this.items, function() {
3160 ( this.instance.options.handle ?
3161 this.item.find( this.instance.options.handle ) : this.item )
3162 .addClass( "ui-sortable-handle" );
3166 _destroy: function() {
3168 .removeClass( "ui-sortable ui-sortable-disabled" )
3169 .find( ".ui-sortable-handle" )
3170 .removeClass( "ui-sortable-handle" );
3171 this._mouseDestroy();
3173 for ( var i = this.items.length - 1; i >= 0; i-- ) {
3174 this.items[i].item.removeData(this.widgetName + "-item");
3180 _mouseCapture: function(event, overrideHandle) {
3181 var currentItem = null,
3182 validHandle = false,
3185 if (this.reverting) {
3189 if(this.options.disabled || this.options.type === "static") {
3193 //We have to refresh the items data once first
3194 this._refreshItems(event);
3196 //Find out if the clicked node (or one of its parents) is a actual item in this.items
3197 $(event.target).parents().each(function() {
3198 if($.data(this, that.widgetName + "-item") === that) {
3199 currentItem = $(this);
3203 if($.data(event.target, that.widgetName + "-item") === that) {
3204 currentItem = $(event.target);
3210 if(this.options.handle && !overrideHandle) {
3211 $(this.options.handle, currentItem).find("*").addBack().each(function() {
3212 if(this === event.target) {
3221 this.currentItem = currentItem;
3222 this._removeCurrentsFromItems();
3227 _mouseStart: function(event, overrideHandle, noActivation) {
3232 this.currentContainer = this;
3234 //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
3235 this.refreshPositions();
3237 //Create and append the visible helper
3238 this.helper = this._createHelper(event);
3240 //Cache the helper size
3241 this._cacheHelperProportions();
3244 * - Position generation -
3245 * This block generates everything position related - it's the core of draggables.
3248 //Cache the margins of the original element
3249 this._cacheMargins();
3251 //Get the next scrolling parent
3252 this.scrollParent = this.helper.scrollParent();
3254 //The element's absolute position on the page minus margins
3255 this.offset = this.currentItem.offset();
3257 top: this.offset.top - this.margins.top,
3258 left: this.offset.left - this.margins.left
3261 $.extend(this.offset, {
3262 click: { //Where the click happened, relative to the element
3263 left: event.pageX - this.offset.left,
3264 top: event.pageY - this.offset.top
3266 parent: this._getParentOffset(),
3267 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
3270 // Only after we got the offset, we can change the helper's position to absolute
3271 // TODO: Still need to figure out a way to make relative sorting possible
3272 this.helper.css("position", "absolute");
3273 this.cssPosition = this.helper.css("position");
3275 //Generate the original position
3276 this.originalPosition = this._generatePosition(event);
3277 this.originalPageX = event.pageX;
3278 this.originalPageY = event.pageY;
3280 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
3281 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
3283 //Cache the former DOM position
3284 this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };
3286 //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way
3287 if(this.helper[0] !== this.currentItem[0]) {
3288 this.currentItem.hide();
3291 //Create the placeholder
3292 this._createPlaceholder();
3294 //Set a containment if given in the options
3296 this._setContainment();
3299 if( o.cursor && o.cursor !== "auto" ) { // cursor option
3300 body = this.document.find( "body" );
3303 this.storedCursor = body.css( "cursor" );
3304 body.css( "cursor", o.cursor );
3306 this.storedStylesheet = $( "<style>*{ cursor: "+o.cursor+" !important; }</style>" ).appendTo( body );
3309 if(o.opacity) { // opacity option
3310 if (this.helper.css("opacity")) {
3311 this._storedOpacity = this.helper.css("opacity");
3313 this.helper.css("opacity", o.opacity);
3316 if(o.zIndex) { // zIndex option
3317 if (this.helper.css("zIndex")) {
3318 this._storedZIndex = this.helper.css("zIndex");
3320 this.helper.css("zIndex", o.zIndex);
3324 if(this.scrollParent[0] !== this.document[0] && this.scrollParent[0].tagName !== "HTML") {
3325 this.overflowOffset = this.scrollParent.offset();
3329 this._trigger("start", event, this._uiHash());
3331 //Recache the helper size
3332 if(!this._preserveHelperProportions) {
3333 this._cacheHelperProportions();
3337 //Post "activate" events to possible containers
3338 if( !noActivation ) {
3339 for ( i = this.containers.length - 1; i >= 0; i-- ) {
3340 this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
3344 //Prepare possible droppables
3345 if($.ui.ddmanager) {
3346 $.ui.ddmanager.current = this;
3349 if ($.ui.ddmanager && !o.dropBehaviour) {
3350 $.ui.ddmanager.prepareOffsets(this, event);
3353 this.dragging = true;
3355 this.helper.addClass("ui-sortable-helper");
3356 this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
3361 _mouseDrag: function(event) {
3362 var i, item, itemElement, intersection,
3366 //Compute the helpers position
3367 this.position = this._generatePosition(event);
3368 this.positionAbs = this._convertPositionTo("absolute");
3370 if (!this.lastPositionAbs) {
3371 this.lastPositionAbs = this.positionAbs;
3375 if(this.options.scroll) {
3376 if(this.scrollParent[0] !== this.document[0] && this.scrollParent[0].tagName !== "HTML") {
3378 if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
3379 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
3380 } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) {
3381 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
3384 if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
3385 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
3386 } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) {
3387 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
3392 if(event.pageY - this.document.scrollTop() < o.scrollSensitivity) {
3393 scrolled = this.document.scrollTop(this.document.scrollTop() - o.scrollSpeed);
3394 } else if(this.window.height() - (event.pageY - this.document.scrollTop()) < o.scrollSensitivity) {
3395 scrolled = this.document.scrollTop(this.document.scrollTop() + o.scrollSpeed);
3398 if(event.pageX - this.document.scrollLeft() < o.scrollSensitivity) {
3399 scrolled = this.document.scrollLeft(this.document.scrollLeft() - o.scrollSpeed);
3400 } else if(this.window.width() - (event.pageX - this.document.scrollLeft()) < o.scrollSensitivity) {
3401 scrolled = this.document.scrollLeft(this.document.scrollLeft() + o.scrollSpeed);
3406 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
3407 $.ui.ddmanager.prepareOffsets(this, event);
3411 //Regenerate the absolute position used for position checks
3412 this.positionAbs = this._convertPositionTo("absolute");
3414 //Set the helper position
3415 if(!this.options.axis || this.options.axis !== "y") {
3416 this.helper[0].style.left = this.position.left+"px";
3418 if(!this.options.axis || this.options.axis !== "x") {
3419 this.helper[0].style.top = this.position.top+"px";
3423 for (i = this.items.length - 1; i >= 0; i--) {
3425 //Cache variables and intersection, continue if no intersection
3426 item = this.items[i];
3427 itemElement = item.item[0];
3428 intersection = this._intersectsWithPointer(item);
3429 if (!intersection) {
3433 // Only put the placeholder inside the current Container, skip all
3434 // items from other containers. This works because when moving
3435 // an item from one container to another the
3436 // currentContainer is switched before the placeholder is moved.
3438 // Without this, moving items in "sub-sortables" can cause
3439 // the placeholder to jitter between the outer and inner container.
3440 if (item.instance !== this.currentContainer) {
3444 // cannot intersect with itself
3445 // no useless actions that have been done before
3446 // no action if the item moved is the parent of the item checked
3447 if (itemElement !== this.currentItem[0] &&
3448 this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement &&
3449 !$.contains(this.placeholder[0], itemElement) &&
3450 (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true)
3453 this.direction = intersection === 1 ? "down" : "up";
3455 if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) {
3456 this._rearrange(event, item);
3461 this._trigger("change", event, this._uiHash());
3466 //Post events to containers
3467 this._contactContainers(event);
3469 //Interconnect with droppables
3470 if($.ui.ddmanager) {
3471 $.ui.ddmanager.drag(this, event);
3475 this._trigger("sort", event, this._uiHash());
3477 this.lastPositionAbs = this.positionAbs;
3482 _mouseStop: function(event, noPropagation) {
3488 //If we are using droppables, inform the manager about the drop
3489 if ($.ui.ddmanager && !this.options.dropBehaviour) {
3490 $.ui.ddmanager.drop(this, event);
3493 if(this.options.revert) {
3495 cur = this.placeholder.offset(),
3496 axis = this.options.axis,
3499 if ( !axis || axis === "x" ) {
3500 animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === this.document[0].body ? 0 : this.offsetParent[0].scrollLeft);
3502 if ( !axis || axis === "y" ) {
3503 animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === this.document[0].body ? 0 : this.offsetParent[0].scrollTop);
3505 this.reverting = true;
3506 $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() {
3510 this._clear(event, noPropagation);
3517 cancel: function() {
3521 this._mouseUp({ target: null });
3523 if(this.options.helper === "original") {
3524 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
3526 this.currentItem.show();
3529 //Post deactivating events to containers
3530 for (var i = this.containers.length - 1; i >= 0; i--){
3531 this.containers[i]._trigger("deactivate", null, this._uiHash(this));
3532 if(this.containers[i].containerCache.over) {
3533 this.containers[i]._trigger("out", null, this._uiHash(this));
3534 this.containers[i].containerCache.over = 0;
3540 if (this.placeholder) {
3541 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
3542 if(this.placeholder[0].parentNode) {
3543 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
3545 if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) {
3546 this.helper.remove();
3556 if(this.domPosition.prev) {
3557 $(this.domPosition.prev).after(this.currentItem);
3559 $(this.domPosition.parent).prepend(this.currentItem);
3567 serialize: function(o) {
3569 var items = this._getItemsAsjQuery(o && o.connected),
3573 $(items).each(function() {
3574 var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/));
3576 str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2]));
3580 if(!str.length && o.key) {
3581 str.push(o.key + "=");
3584 return str.join("&");
3588 toArray: function(o) {
3590 var items = this._getItemsAsjQuery(o && o.connected),
3595 items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); });
3600 /* Be careful with the following core functions */
3601 _intersectsWith: function(item) {
3603 var x1 = this.positionAbs.left,
3604 x2 = x1 + this.helperProportions.width,
3605 y1 = this.positionAbs.top,
3606 y2 = y1 + this.helperProportions.height,
3610 b = t + item.height,
3611 dyClick = this.offset.click.top,
3612 dxClick = this.offset.click.left,
3613 isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ),
3614 isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ),
3615 isOverElement = isOverElementHeight && isOverElementWidth;
3617 if ( this.options.tolerance === "pointer" ||
3618 this.options.forcePointerForContainers ||
3619 (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"])
3621 return isOverElement;
3624 return (l < x1 + (this.helperProportions.width / 2) && // Right Half
3625 x2 - (this.helperProportions.width / 2) < r && // Left Half
3626 t < y1 + (this.helperProportions.height / 2) && // Bottom Half
3627 y2 - (this.helperProportions.height / 2) < b ); // Top Half
3632 _intersectsWithPointer: function(item) {
3634 var isOverElementHeight = (this.options.axis === "x") || this._isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
3635 isOverElementWidth = (this.options.axis === "y") || this._isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
3636 isOverElement = isOverElementHeight && isOverElementWidth,
3637 verticalDirection = this._getDragVerticalDirection(),
3638 horizontalDirection = this._getDragHorizontalDirection();
3640 if (!isOverElement) {
3644 return this.floating ?
3645 ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 )
3646 : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) );
3650 _intersectsWithSides: function(item) {
3652 var isOverBottomHalf = this._isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
3653 isOverRightHalf = this._isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
3654 verticalDirection = this._getDragVerticalDirection(),
3655 horizontalDirection = this._getDragHorizontalDirection();
3657 if (this.floating && horizontalDirection) {
3658 return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf));
3660 return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf));
3665 _getDragVerticalDirection: function() {
3666 var delta = this.positionAbs.top - this.lastPositionAbs.top;
3667 return delta !== 0 && (delta > 0 ? "down" : "up");
3670 _getDragHorizontalDirection: function() {
3671 var delta = this.positionAbs.left - this.lastPositionAbs.left;
3672 return delta !== 0 && (delta > 0 ? "right" : "left");
3675 refresh: function(event) {
3676 this._refreshItems(event);
3677 this._setHandleClassName();
3678 this.refreshPositions();
3682 _connectWith: function() {
3683 var options = this.options;
3684 return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith;
3687 _getItemsAsjQuery: function(connected) {
3689 var i, j, cur, inst,
3692 connectWith = this._connectWith();
3694 if(connectWith && connected) {
3695 for (i = connectWith.length - 1; i >= 0; i--){
3696 cur = $(connectWith[i], this.document[0]);
3697 for ( j = cur.length - 1; j >= 0; j--){
3698 inst = $.data(cur[j], this.widgetFullName);
3699 if(inst && inst !== this && !inst.options.disabled) {
3700 queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), inst]);
3706 queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), this]);
3708 function addItems() {
3711 for (i = queries.length - 1; i >= 0; i--){
3712 queries[i][0].each( addItems );
3719 _removeCurrentsFromItems: function() {
3721 var list = this.currentItem.find(":data(" + this.widgetName + "-item)");
3723 this.items = $.grep(this.items, function (item) {
3724 for (var j=0; j < list.length; j++) {
3725 if(list[j] === item.item[0]) {
3734 _refreshItems: function(event) {
3737 this.containers = [this];
3739 var i, j, cur, inst, targetData, _queries, item, queriesLength,
3741 queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]],
3742 connectWith = this._connectWith();
3744 if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down
3745 for (i = connectWith.length - 1; i >= 0; i--){
3746 cur = $(connectWith[i], this.document[0]);
3747 for (j = cur.length - 1; j >= 0; j--){
3748 inst = $.data(cur[j], this.widgetFullName);
3749 if(inst && inst !== this && !inst.options.disabled) {
3750 queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
3751 this.containers.push(inst);
3757 for (i = queries.length - 1; i >= 0; i--) {
3758 targetData = queries[i][1];
3759 _queries = queries[i][0];
3761 for (j=0, queriesLength = _queries.length; j < queriesLength; j++) {
3762 item = $(_queries[j]);
3764 item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager)
3768 instance: targetData,
3769 width: 0, height: 0,
3777 refreshPositions: function(fast) {
3779 // Determine whether items are being displayed horizontally
3780 this.floating = this.items.length ?
3781 this.options.axis === "x" || this._isFloating( this.items[ 0 ].item ) :
3784 //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
3785 if(this.offsetParent && this.helper) {
3786 this.offset.parent = this._getParentOffset();
3791 for (i = this.items.length - 1; i >= 0; i--){
3792 item = this.items[i];
3794 //We ignore calculating positions of all connected containers when we're not over them
3795 if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) {
3799 t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
3802 item.width = t.outerWidth();
3803 item.height = t.outerHeight();
3811 if(this.options.custom && this.options.custom.refreshContainers) {
3812 this.options.custom.refreshContainers.call(this);
3814 for (i = this.containers.length - 1; i >= 0; i--){
3815 p = this.containers[i].element.offset();
3816 this.containers[i].containerCache.left = p.left;
3817 this.containers[i].containerCache.top = p.top;
3818 this.containers[i].containerCache.width = this.containers[i].element.outerWidth();
3819 this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
3826 _createPlaceholder: function(that) {
3827 that = that || this;
3831 if(!o.placeholder || o.placeholder.constructor === String) {
3832 className = o.placeholder;
3834 element: function() {
3836 var nodeName = that.currentItem[0].nodeName.toLowerCase(),
3837 element = $( "<" + nodeName + ">", that.document[0] )
3838 .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder")
3839 .removeClass("ui-sortable-helper");
3841 if ( nodeName === "tbody" ) {
3842 that._createTrPlaceholder(
3843 that.currentItem.find( "tr" ).eq( 0 ),
3844 $( "<tr>", that.document[ 0 ] ).appendTo( element )
3846 } else if ( nodeName === "tr" ) {
3847 that._createTrPlaceholder( that.currentItem, element );
3848 } else if ( nodeName === "img" ) {
3849 element.attr( "src", that.currentItem.attr( "src" ) );
3853 element.css( "visibility", "hidden" );
3858 update: function(container, p) {
3860 // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that
3861 // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified
3862 if(className && !o.forcePlaceholderSize) {
3866 //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item
3867 if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); }
3868 if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); }
3873 //Create the placeholder
3874 that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem));
3876 //Append it after the actual current item
3877 that.currentItem.after(that.placeholder);
3879 //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
3880 o.placeholder.update(that, that.placeholder);
3884 _createTrPlaceholder: function( sourceTr, targetTr ) {
3887 sourceTr.children().each(function() {
3888 $( "<td> </td>", that.document[ 0 ] )
3889 .attr( "colspan", $( this ).attr( "colspan" ) || 1 )
3890 .appendTo( targetTr );
3894 _contactContainers: function(event) {
3895 var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom, floating, axis,
3896 innermostContainer = null,
3897 innermostIndex = null;
3899 // get innermost container that intersects with item
3900 for (i = this.containers.length - 1; i >= 0; i--) {
3902 // never consider a container that's located within the item itself
3903 if($.contains(this.currentItem[0], this.containers[i].element[0])) {
3907 if(this._intersectsWith(this.containers[i].containerCache)) {
3909 // if we've already found a container and it's more "inner" than this, then continue
3910 if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) {
3914 innermostContainer = this.containers[i];
3918 // container doesn't intersect. trigger "out" event if necessary
3919 if(this.containers[i].containerCache.over) {
3920 this.containers[i]._trigger("out", event, this._uiHash(this));
3921 this.containers[i].containerCache.over = 0;
3927 // if no intersecting containers found, return
3928 if(!innermostContainer) {
3932 // move the item into the container if it's not there already
3933 if(this.containers.length === 1) {
3934 if (!this.containers[innermostIndex].containerCache.over) {
3935 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
3936 this.containers[innermostIndex].containerCache.over = 1;
3940 //When entering a new container, we will find the item with the least distance and append our item near it
3942 itemWithLeastDistance = null;
3943 floating = innermostContainer.floating || this._isFloating(this.currentItem);
3944 posProperty = floating ? "left" : "top";
3945 sizeProperty = floating ? "width" : "height";
3946 axis = floating ? "clientX" : "clientY";
3948 for (j = this.items.length - 1; j >= 0; j--) {
3949 if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) {
3952 if(this.items[j].item[0] === this.currentItem[0]) {
3956 cur = this.items[j].item.offset()[posProperty];
3958 if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) {
3962 if ( Math.abs( event[ axis ] - cur ) < dist ) {
3963 dist = Math.abs( event[ axis ] - cur );
3964 itemWithLeastDistance = this.items[ j ];
3965 this.direction = nearBottom ? "up": "down";
3969 //Check if dropOnEmpty is enabled
3970 if(!itemWithLeastDistance && !this.options.dropOnEmpty) {
3974 if(this.currentContainer === this.containers[innermostIndex]) {
3975 if ( !this.currentContainer.containerCache.over ) {
3976 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() );
3977 this.currentContainer.containerCache.over = 1;
3982 itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true);
3983 this._trigger("change", event, this._uiHash());
3984 this.containers[innermostIndex]._trigger("change", event, this._uiHash(this));
3985 this.currentContainer = this.containers[innermostIndex];
3987 //Update the placeholder
3988 this.options.placeholder.update(this.currentContainer, this.placeholder);
3990 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
3991 this.containers[innermostIndex].containerCache.over = 1;
3997 _createHelper: function(event) {
3999 var o = this.options,
4000 helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem);
4002 //Add the helper to the DOM if that didn't happen already
4003 if(!helper.parents("body").length) {
4004 $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
4007 if(helper[0] === this.currentItem[0]) {
4008 this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") };
4011 if(!helper[0].style.width || o.forceHelperSize) {
4012 helper.width(this.currentItem.width());
4014 if(!helper[0].style.height || o.forceHelperSize) {
4015 helper.height(this.currentItem.height());
4022 _adjustOffsetFromHelper: function(obj) {
4023 if (typeof obj === "string") {
4024 obj = obj.split(" ");
4026 if ($.isArray(obj)) {
4027 obj = {left: +obj[0], top: +obj[1] || 0};
4029 if ("left" in obj) {
4030 this.offset.click.left = obj.left + this.margins.left;
4032 if ("right" in obj) {
4033 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
4036 this.offset.click.top = obj.top + this.margins.top;
4038 if ("bottom" in obj) {
4039 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
4043 _getParentOffset: function() {
4046 //Get the offsetParent and cache its position
4047 this.offsetParent = this.helper.offsetParent();
4048 var po = this.offsetParent.offset();
4050 // This is a special case where we need to modify a offset calculated on start, since the following happened:
4051 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
4052 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
4053 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
4054 if(this.cssPosition === "absolute" && this.scrollParent[0] !== this.document[0] && $.contains(this.scrollParent[0], this.offsetParent[0])) {
4055 po.left += this.scrollParent.scrollLeft();
4056 po.top += this.scrollParent.scrollTop();
4059 // This needs to be actually done for all browsers, since pageX/pageY includes this information
4060 // with an ugly IE fix
4061 if( this.offsetParent[0] === this.document[0].body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
4062 po = { top: 0, left: 0 };
4066 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
4067 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
4072 _getRelativeOffset: function() {
4074 if(this.cssPosition === "relative") {
4075 var p = this.currentItem.position();
4077 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
4078 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
4081 return { top: 0, left: 0 };
4086 _cacheMargins: function() {
4088 left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
4089 top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
4093 _cacheHelperProportions: function() {
4094 this.helperProportions = {
4095 width: this.helper.outerWidth(),
4096 height: this.helper.outerHeight()
4100 _setContainment: function() {
4104 if(o.containment === "parent") {
4105 o.containment = this.helper[0].parentNode;
4107 if(o.containment === "document" || o.containment === "window") {
4108 this.containment = [
4109 0 - this.offset.relative.left - this.offset.parent.left,
4110 0 - this.offset.relative.top - this.offset.parent.top,
4111 o.containment === "document" ? this.document.width() : this.window.width() - this.helperProportions.width - this.margins.left,
4112 (o.containment === "document" ? this.document.width() : this.window.height() || this.document[0].body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
4116 if(!(/^(document|window|parent)$/).test(o.containment)) {
4117 ce = $(o.containment)[0];
4118 co = $(o.containment).offset();
4119 over = ($(ce).css("overflow") !== "hidden");
4121 this.containment = [
4122 co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
4123 co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
4124 co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left,
4125 co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top
4131 _convertPositionTo: function(d, pos) {
4134 pos = this.position;
4136 var mod = d === "absolute" ? 1 : -1,
4137 scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== this.document[0] && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent,
4138 scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
4142 pos.top + // The absolute mouse position
4143 this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
4144 this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
4145 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
4148 pos.left + // The absolute mouse position
4149 this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
4150 this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
4151 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
4157 _generatePosition: function(event) {
4161 pageX = event.pageX,
4162 pageY = event.pageY,
4163 scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== this.document[0] && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
4165 // This is another very weird special case that only happens for relative elements:
4166 // 1. If the css position is relative
4167 // 2. and the scroll parent is the document or similar to the offset parent
4168 // we have to refresh the relative offset during the scroll so there are no jumps
4169 if(this.cssPosition === "relative" && !(this.scrollParent[0] !== this.document[0] && this.scrollParent[0] !== this.offsetParent[0])) {
4170 this.offset.relative = this._getRelativeOffset();
4174 * - Position constraining -
4175 * Constrain the position to a mix of grid, containment.
4178 if(this.originalPosition) { //If we are not dragging yet, we won't check for options
4180 if(this.containment) {
4181 if(event.pageX - this.offset.click.left < this.containment[0]) {
4182 pageX = this.containment[0] + this.offset.click.left;
4184 if(event.pageY - this.offset.click.top < this.containment[1]) {
4185 pageY = this.containment[1] + this.offset.click.top;
4187 if(event.pageX - this.offset.click.left > this.containment[2]) {
4188 pageX = this.containment[2] + this.offset.click.left;
4190 if(event.pageY - this.offset.click.top > this.containment[3]) {
4191 pageY = this.containment[3] + this.offset.click.top;
4196 top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
4197 pageY = this.containment ? ( (top - this.offset.click.top >= this.containment[1] && top - this.offset.click.top <= this.containment[3]) ? top : ((top - this.offset.click.top >= this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
4199 left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
4200 pageX = this.containment ? ( (left - this.offset.click.left >= this.containment[0] && left - this.offset.click.left <= this.containment[2]) ? left : ((left - this.offset.click.left >= this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
4207 pageY - // The absolute mouse position
4208 this.offset.click.top - // Click offset (relative to the element)
4209 this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
4210 this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
4211 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
4214 pageX - // The absolute mouse position
4215 this.offset.click.left - // Click offset (relative to the element)
4216 this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
4217 this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
4218 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
4224 _rearrange: function(event, i, a, hardRefresh) {
4226 a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction === "down" ? i.item[0] : i.item[0].nextSibling));
4228 //Various things done here to improve the performance:
4229 // 1. we create a setTimeout, that calls refreshPositions
4230 // 2. on the instance, we have a counter variable, that get's higher after every append
4231 // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
4232 // 4. this lets only the last addition to the timeout stack through
4233 this.counter = this.counter ? ++this.counter : 1;
4234 var counter = this.counter;
4236 this._delay(function() {
4237 if(counter === this.counter) {
4238 this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
4244 _clear: function(event, noPropagation) {
4246 this.reverting = false;
4247 // We delay all events that have to be triggered to after the point where the placeholder has been removed and
4248 // everything else normalized again
4250 delayedTriggers = [];
4252 // We first have to update the dom position of the actual currentItem
4253 // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
4254 if(!this._noFinalSort && this.currentItem.parent().length) {
4255 this.placeholder.before(this.currentItem);
4257 this._noFinalSort = null;
4259 if(this.helper[0] === this.currentItem[0]) {
4260 for(i in this._storedCSS) {
4261 if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") {
4262 this._storedCSS[i] = "";
4265 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
4267 this.currentItem.show();
4270 if(this.fromOutside && !noPropagation) {
4271 delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
4273 if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) {
4274 delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed
4277 // Check if the items Container has Changed and trigger appropriate
4279 if (this !== this.currentContainer) {
4280 if(!noPropagation) {
4281 delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); });
4282 delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
4283 delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
4288 //Post events to containers
4289 function delayEvent( type, instance, container ) {
4290 return function( event ) {
4291 container._trigger( type, event, instance._uiHash( instance ) );
4294 for (i = this.containers.length - 1; i >= 0; i--){
4295 if (!noPropagation) {
4296 delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) );
4298 if(this.containers[i].containerCache.over) {
4299 delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) );
4300 this.containers[i].containerCache.over = 0;
4304 //Do what was originally in plugins
4305 if ( this.storedCursor ) {
4306 this.document.find( "body" ).css( "cursor", this.storedCursor );
4307 this.storedStylesheet.remove();
4309 if(this._storedOpacity) {
4310 this.helper.css("opacity", this._storedOpacity);
4312 if(this._storedZIndex) {
4313 this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex);
4316 this.dragging = false;
4318 if(!noPropagation) {
4319 this._trigger("beforeStop", event, this._uiHash());
4322 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
4323 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
4325 if ( !this.cancelHelperRemoval ) {
4326 if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
4327 this.helper.remove();
4332 if(!noPropagation) {
4333 for (i=0; i < delayedTriggers.length; i++) {
4334 delayedTriggers[i].call(this, event);
4335 } //Trigger all delayed events
4336 this._trigger("stop", event, this._uiHash());
4339 this.fromOutside = false;
4340 return !this.cancelHelperRemoval;
4344 _trigger: function() {
4345 if ($.Widget.prototype._trigger.apply(this, arguments) === false) {
4350 _uiHash: function(_inst) {
4351 var inst = _inst || this;
4353 helper: inst.helper,
4354 placeholder: inst.placeholder || $([]),
4355 position: inst.position,
4356 originalPosition: inst.originalPosition,
4357 offset: inst.positionAbs,
4358 item: inst.currentItem,
4359 sender: _inst ? _inst.element : null
4367 * jQuery UI Accordion 1.11.4
4368 * http://jqueryui.com
4370 * Copyright jQuery Foundation and other contributors
4371 * Released under the MIT license.
4372 * http://jquery.org/license
4374 * http://api.jqueryui.com/accordion/
4378 var accordion = $.widget( "ui.accordion", {
4385 header: "> li > :first-child,> :not(li):even",
4386 heightStyle: "auto",
4388 activeHeader: "ui-icon-triangle-1-s",
4389 header: "ui-icon-triangle-1-e"
4394 beforeActivate: null
4398 borderTopWidth: "hide",
4399 borderBottomWidth: "hide",
4401 paddingBottom: "hide",
4406 borderTopWidth: "show",
4407 borderBottomWidth: "show",
4409 paddingBottom: "show",
4413 _create: function() {
4414 var options = this.options;
4415 this.prevShow = this.prevHide = $();
4416 this.element.addClass( "ui-accordion ui-widget ui-helper-reset" )
4418 .attr( "role", "tablist" );
4420 // don't allow collapsible: false and active: false / null
4421 if ( !options.collapsible && (options.active === false || options.active == null) ) {
4425 this._processPanels();
4426 // handle negative values
4427 if ( options.active < 0 ) {
4428 options.active += this.headers.length;
4433 _getCreateEventData: function() {
4435 header: this.active,
4436 panel: !this.active.length ? $() : this.active.next()
4440 _createIcons: function() {
4441 var icons = this.options.icons;
4444 .addClass( "ui-accordion-header-icon ui-icon " + icons.header )
4445 .prependTo( this.headers );
4446 this.active.children( ".ui-accordion-header-icon" )
4447 .removeClass( icons.header )
4448 .addClass( icons.activeHeader );
4449 this.headers.addClass( "ui-accordion-icons" );
4453 _destroyIcons: function() {
4455 .removeClass( "ui-accordion-icons" )
4456 .children( ".ui-accordion-header-icon" )
4460 _destroy: function() {
4463 // clean up main element
4465 .removeClass( "ui-accordion ui-widget ui-helper-reset" )
4466 .removeAttr( "role" );
4470 .removeClass( "ui-accordion-header ui-accordion-header-active ui-state-default " +
4471 "ui-corner-all ui-state-active ui-state-disabled ui-corner-top" )
4472 .removeAttr( "role" )
4473 .removeAttr( "aria-expanded" )
4474 .removeAttr( "aria-selected" )
4475 .removeAttr( "aria-controls" )
4476 .removeAttr( "tabIndex" )
4479 this._destroyIcons();
4481 // clean up content panels
4482 contents = this.headers.next()
4483 .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom " +
4484 "ui-accordion-content ui-accordion-content-active ui-state-disabled" )
4485 .css( "display", "" )
4486 .removeAttr( "role" )
4487 .removeAttr( "aria-hidden" )
4488 .removeAttr( "aria-labelledby" )
4491 if ( this.options.heightStyle !== "content" ) {
4492 contents.css( "height", "" );
4496 _setOption: function( key, value ) {
4497 if ( key === "active" ) {
4498 // _activate() will handle invalid values and update this.options
4499 this._activate( value );
4503 if ( key === "event" ) {
4504 if ( this.options.event ) {
4505 this._off( this.headers, this.options.event );
4507 this._setupEvents( value );
4510 this._super( key, value );
4512 // setting collapsible: false while collapsed; open first panel
4513 if ( key === "collapsible" && !value && this.options.active === false ) {
4514 this._activate( 0 );
4517 if ( key === "icons" ) {
4518 this._destroyIcons();
4520 this._createIcons();
4524 // #5332 - opacity doesn't cascade to positioned elements in IE
4525 // so we need to add the disabled class to the headers and panels
4526 if ( key === "disabled" ) {
4528 .toggleClass( "ui-state-disabled", !!value )
4529 .attr( "aria-disabled", value );
4530 this.headers.add( this.headers.next() )
4531 .toggleClass( "ui-state-disabled", !!value );
4535 _keydown: function( event ) {
4536 if ( event.altKey || event.ctrlKey ) {
4540 var keyCode = $.ui.keyCode,
4541 length = this.headers.length,
4542 currentIndex = this.headers.index( event.target ),
4545 switch ( event.keyCode ) {
4548 toFocus = this.headers[ ( currentIndex + 1 ) % length ];
4552 toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
4556 this._eventHandler( event );
4559 toFocus = this.headers[ 0 ];
4562 toFocus = this.headers[ length - 1 ];
4567 $( event.target ).attr( "tabIndex", -1 );
4568 $( toFocus ).attr( "tabIndex", 0 );
4570 event.preventDefault();
4574 _panelKeyDown: function( event ) {
4575 if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
4576 $( event.currentTarget ).prev().focus();
4580 refresh: function() {
4581 var options = this.options;
4582 this._processPanels();
4584 // was collapsed or no panel
4585 if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) {
4586 options.active = false;
4588 // active false only when collapsible is true
4589 } else if ( options.active === false ) {
4590 this._activate( 0 );
4591 // was active, but active panel is gone
4592 } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
4593 // all remaining panel are disabled
4594 if ( this.headers.length === this.headers.find(".ui-state-disabled").length ) {
4595 options.active = false;
4597 // activate previous panel
4599 this._activate( Math.max( 0, options.active - 1 ) );
4601 // was active, active panel still exists
4603 // make sure active index is correct
4604 options.active = this.headers.index( this.active );
4607 this._destroyIcons();
4612 _processPanels: function() {
4613 var prevHeaders = this.headers,
4614 prevPanels = this.panels;
4616 this.headers = this.element.find( this.options.header )
4617 .addClass( "ui-accordion-header ui-state-default ui-corner-all" );
4619 this.panels = this.headers.next()
4620 .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" )
4621 .filter( ":not(.ui-accordion-content-active)" )
4624 // Avoid memory leaks (#10056)
4626 this._off( prevHeaders.not( this.headers ) );
4627 this._off( prevPanels.not( this.panels ) );
4631 _refresh: function() {
4633 options = this.options,
4634 heightStyle = options.heightStyle,
4635 parent = this.element.parent();
4637 this.active = this._findActive( options.active )
4638 .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" )
4639 .removeClass( "ui-corner-all" );
4641 .addClass( "ui-accordion-content-active" )
4645 .attr( "role", "tab" )
4647 var header = $( this ),
4648 headerId = header.uniqueId().attr( "id" ),
4649 panel = header.next(),
4650 panelId = panel.uniqueId().attr( "id" );
4651 header.attr( "aria-controls", panelId );
4652 panel.attr( "aria-labelledby", headerId );
4655 .attr( "role", "tabpanel" );
4660 "aria-selected": "false",
4661 "aria-expanded": "false",
4666 "aria-hidden": "true"
4670 // make sure at least one header is in the tab order
4671 if ( !this.active.length ) {
4672 this.headers.eq( 0 ).attr( "tabIndex", 0 );
4675 "aria-selected": "true",
4676 "aria-expanded": "true",
4681 "aria-hidden": "false"
4685 this._createIcons();
4687 this._setupEvents( options.event );
4689 if ( heightStyle === "fill" ) {
4690 maxHeight = parent.height();
4691 this.element.siblings( ":visible" ).each(function() {
4692 var elem = $( this ),
4693 position = elem.css( "position" );
4695 if ( position === "absolute" || position === "fixed" ) {
4698 maxHeight -= elem.outerHeight( true );
4701 this.headers.each(function() {
4702 maxHeight -= $( this ).outerHeight( true );
4707 $( this ).height( Math.max( 0, maxHeight -
4708 $( this ).innerHeight() + $( this ).height() ) );
4710 .css( "overflow", "auto" );
4711 } else if ( heightStyle === "auto" ) {
4715 maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
4717 .height( maxHeight );
4721 _activate: function( index ) {
4722 var active = this._findActive( index )[ 0 ];
4724 // trying to activate the already active panel
4725 if ( active === this.active[ 0 ] ) {
4729 // trying to collapse, simulate a click on the currently active header
4730 active = active || this.active[ 0 ];
4732 this._eventHandler({
4734 currentTarget: active,
4735 preventDefault: $.noop
4739 _findActive: function( selector ) {
4740 return typeof selector === "number" ? this.headers.eq( selector ) : $();
4743 _setupEvents: function( event ) {
4748 $.each( event.split( " " ), function( index, eventName ) {
4749 events[ eventName ] = "_eventHandler";
4753 this._off( this.headers.add( this.headers.next() ) );
4754 this._on( this.headers, events );
4755 this._on( this.headers.next(), { keydown: "_panelKeyDown" });
4756 this._hoverable( this.headers );
4757 this._focusable( this.headers );
4760 _eventHandler: function( event ) {
4761 var options = this.options,
4762 active = this.active,
4763 clicked = $( event.currentTarget ),
4764 clickedIsActive = clicked[ 0 ] === active[ 0 ],
4765 collapsing = clickedIsActive && options.collapsible,
4766 toShow = collapsing ? $() : clicked.next(),
4767 toHide = active.next(),
4771 newHeader: collapsing ? $() : clicked,
4775 event.preventDefault();
4778 // click on active header, but not collapsible
4779 ( clickedIsActive && !options.collapsible ) ||
4780 // allow canceling activation
4781 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
4785 options.active = collapsing ? false : this.headers.index( clicked );
4787 // when the call to ._toggle() comes after the class changes
4788 // it causes a very odd bug in IE 8 (see #6720)
4789 this.active = clickedIsActive ? $() : clicked;
4790 this._toggle( eventData );
4793 // corner classes on the previously active header stay after the animation
4794 active.removeClass( "ui-accordion-header-active ui-state-active" );
4795 if ( options.icons ) {
4796 active.children( ".ui-accordion-header-icon" )
4797 .removeClass( options.icons.activeHeader )
4798 .addClass( options.icons.header );
4801 if ( !clickedIsActive ) {
4803 .removeClass( "ui-corner-all" )
4804 .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" );
4805 if ( options.icons ) {
4806 clicked.children( ".ui-accordion-header-icon" )
4807 .removeClass( options.icons.header )
4808 .addClass( options.icons.activeHeader );
4813 .addClass( "ui-accordion-content-active" );
4817 _toggle: function( data ) {
4818 var toShow = data.newPanel,
4819 toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
4821 // handle activating a panel during the animation for another activation
4822 this.prevShow.add( this.prevHide ).stop( true, true );
4823 this.prevShow = toShow;
4824 this.prevHide = toHide;
4826 if ( this.options.animate ) {
4827 this._animate( toShow, toHide, data );
4831 this._toggleComplete( data );
4835 "aria-hidden": "true"
4837 toHide.prev().attr({
4838 "aria-selected": "false",
4839 "aria-expanded": "false"
4841 // if we're switching panels, remove the old header from the tab order
4842 // if we're opening from collapsed state, remove the previous header from the tab order
4843 // if we're collapsing, then keep the collapsing header in the tab order
4844 if ( toShow.length && toHide.length ) {
4845 toHide.prev().attr({
4847 "aria-expanded": "false"
4849 } else if ( toShow.length ) {
4850 this.headers.filter(function() {
4851 return parseInt( $( this ).attr( "tabIndex" ), 10 ) === 0;
4853 .attr( "tabIndex", -1 );
4857 .attr( "aria-hidden", "false" )
4860 "aria-selected": "true",
4861 "aria-expanded": "true",
4866 _animate: function( toShow, toHide, data ) {
4867 var total, easing, duration,
4870 boxSizing = toShow.css( "box-sizing" ),
4871 down = toShow.length &&
4872 ( !toHide.length || ( toShow.index() < toHide.index() ) ),
4873 animate = this.options.animate || {},
4874 options = down && animate.down || animate,
4875 complete = function() {
4876 that._toggleComplete( data );
4879 if ( typeof options === "number" ) {
4882 if ( typeof options === "string" ) {
4885 // fall back from options to animation in case of partial down settings
4886 easing = easing || options.easing || animate.easing;
4887 duration = duration || options.duration || animate.duration;
4889 if ( !toHide.length ) {
4890 return toShow.animate( this.showProps, duration, easing, complete );
4892 if ( !toShow.length ) {
4893 return toHide.animate( this.hideProps, duration, easing, complete );
4896 total = toShow.show().outerHeight();
4897 toHide.animate( this.hideProps, {
4900 step: function( now, fx ) {
4901 fx.now = Math.round( now );
4906 .animate( this.showProps, {
4910 step: function( now, fx ) {
4911 fx.now = Math.round( now );
4912 if ( fx.prop !== "height" ) {
4913 if ( boxSizing === "content-box" ) {
4916 } else if ( that.options.heightStyle !== "content" ) {
4917 fx.now = Math.round( total - toHide.outerHeight() - adjust );
4924 _toggleComplete: function( data ) {
4925 var toHide = data.oldPanel;
4928 .removeClass( "ui-accordion-content-active" )
4930 .removeClass( "ui-corner-top" )
4931 .addClass( "ui-corner-all" );
4933 // Work around for rendering bug in IE (#5421)
4934 if ( toHide.length ) {
4935 toHide.parent()[ 0 ].className = toHide.parent()[ 0 ].className;
4937 this._trigger( "activate", null, data );
4943 * jQuery UI Menu 1.11.4
4944 * http://jqueryui.com
4946 * Copyright jQuery Foundation and other contributors
4947 * Released under the MIT license.
4948 * http://jquery.org/license
4950 * http://api.jqueryui.com/menu/
4954 var menu = $.widget( "ui.menu", {
4956 defaultElement: "<ul>",
4960 submenu: "ui-icon-carat-1-e"
4976 _create: function() {
4977 this.activeMenu = this.element;
4979 // Flag used to prevent firing of the click handler
4980 // as the event bubbles up through nested menus
4981 this.mouseHandled = false;
4984 .addClass( "ui-menu ui-widget ui-widget-content" )
4985 .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length )
4987 role: this.options.role,
4991 if ( this.options.disabled ) {
4993 .addClass( "ui-state-disabled" )
4994 .attr( "aria-disabled", "true" );
4998 // Prevent focus from sticking to links inside menu after clicking
4999 // them (focus should always stay on UL during navigation).
5000 "mousedown .ui-menu-item": function( event ) {
5001 event.preventDefault();
5003 "click .ui-menu-item": function( event ) {
5004 var target = $( event.target );
5005 if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
5006 this.select( event );
5008 // Only set the mouseHandled flag if the event will bubble, see #9469.
5009 if ( !event.isPropagationStopped() ) {
5010 this.mouseHandled = true;
5013 // Open submenu on click
5014 if ( target.has( ".ui-menu" ).length ) {
5015 this.expand( event );
5016 } else if ( !this.element.is( ":focus" ) && $( this.document[ 0 ].activeElement ).closest( ".ui-menu" ).length ) {
5018 // Redirect focus to the menu
5019 this.element.trigger( "focus", [ true ] );
5021 // If the active item is on the top level, let it stay active.
5022 // Otherwise, blur the active item since it is no longer visible.
5023 if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
5024 clearTimeout( this.timer );
5029 "mouseenter .ui-menu-item": function( event ) {
5030 // Ignore mouse events while typeahead is active, see #10458.
5031 // Prevents focusing the wrong item when typeahead causes a scroll while the mouse
5032 // is over an item in the menu
5033 if ( this.previousFilter ) {
5036 var target = $( event.currentTarget );
5037 // Remove ui-state-active class from siblings of the newly focused menu item
5038 // to avoid a jump caused by adjacent elements both having a class with a border
5039 target.siblings( ".ui-state-active" ).removeClass( "ui-state-active" );
5040 this.focus( event, target );
5042 mouseleave: "collapseAll",
5043 "mouseleave .ui-menu": "collapseAll",
5044 focus: function( event, keepActiveItem ) {
5045 // If there's already an active item, keep it active
5046 // If not, activate the first item
5047 var item = this.active || this.element.find( this.options.items ).eq( 0 );
5049 if ( !keepActiveItem ) {
5050 this.focus( event, item );
5053 blur: function( event ) {
5054 this._delay(function() {
5055 if ( !$.contains( this.element[0], this.document[0].activeElement ) ) {
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 // Destroy (sub)menus
5081 .removeAttr( "aria-activedescendant" )
5082 .find( ".ui-menu" ).addBack()
5083 .removeClass( "ui-menu ui-widget ui-widget-content ui-menu-icons ui-front" )
5084 .removeAttr( "role" )
5085 .removeAttr( "tabIndex" )
5086 .removeAttr( "aria-labelledby" )
5087 .removeAttr( "aria-expanded" )
5088 .removeAttr( "aria-hidden" )
5089 .removeAttr( "aria-disabled" )
5093 // Destroy menu items
5094 this.element.find( ".ui-menu-item" )
5095 .removeClass( "ui-menu-item" )
5096 .removeAttr( "role" )
5097 .removeAttr( "aria-disabled" )
5099 .removeClass( "ui-state-hover" )
5100 .removeAttr( "tabIndex" )
5101 .removeAttr( "role" )
5102 .removeAttr( "aria-haspopup" )
5103 .children().each( function() {
5104 var elem = $( this );
5105 if ( elem.data( "ui-menu-submenu-carat" ) ) {
5110 // Destroy menu dividers
5111 this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" );
5114 _keydown: function( event ) {
5115 var match, prev, character, skip,
5116 preventDefault = true;
5118 switch ( event.keyCode ) {
5119 case $.ui.keyCode.PAGE_UP:
5120 this.previousPage( event );
5122 case $.ui.keyCode.PAGE_DOWN:
5123 this.nextPage( event );
5125 case $.ui.keyCode.HOME:
5126 this._move( "first", "first", event );
5128 case $.ui.keyCode.END:
5129 this._move( "last", "last", event );
5131 case $.ui.keyCode.UP:
5132 this.previous( event );
5134 case $.ui.keyCode.DOWN:
5137 case $.ui.keyCode.LEFT:
5138 this.collapse( event );
5140 case $.ui.keyCode.RIGHT:
5141 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
5142 this.expand( event );
5145 case $.ui.keyCode.ENTER:
5146 case $.ui.keyCode.SPACE:
5147 this._activate( event );
5149 case $.ui.keyCode.ESCAPE:
5150 this.collapse( event );
5153 preventDefault = false;
5154 prev = this.previousFilter || "";
5155 character = String.fromCharCode( event.keyCode );
5158 clearTimeout( this.filterTimer );
5160 if ( character === prev ) {
5163 character = prev + character;
5166 match = this._filterMenuItems( character );
5167 match = skip && match.index( this.active.next() ) !== -1 ?
5168 this.active.nextAll( ".ui-menu-item" ) :
5171 // If no matches on the current filter, reset to the last character pressed
5172 // to move down the menu to the first item that starts with that character
5173 if ( !match.length ) {
5174 character = String.fromCharCode( event.keyCode );
5175 match = this._filterMenuItems( character );
5178 if ( match.length ) {
5179 this.focus( event, match );
5180 this.previousFilter = character;
5181 this.filterTimer = this._delay(function() {
5182 delete this.previousFilter;
5185 delete this.previousFilter;
5189 if ( preventDefault ) {
5190 event.preventDefault();
5194 _activate: function( event ) {
5195 if ( !this.active.is( ".ui-state-disabled" ) ) {
5196 if ( this.active.is( "[aria-haspopup='true']" ) ) {
5197 this.expand( event );
5199 this.select( event );
5204 refresh: function() {
5207 icon = this.options.icons.submenu,
5208 submenus = this.element.find( this.options.menus );
5210 this.element.toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length );
5212 // Initialize nested menus
5213 submenus.filter( ":not(.ui-menu)" )
5214 .addClass( "ui-menu ui-widget ui-widget-content ui-front" )
5217 role: this.options.role,
5218 "aria-hidden": "true",
5219 "aria-expanded": "false"
5222 var menu = $( this ),
5223 item = menu.parent(),
5224 submenuCarat = $( "<span>" )
5225 .addClass( "ui-menu-icon ui-icon " + icon )
5226 .data( "ui-menu-submenu-carat", true );
5229 .attr( "aria-haspopup", "true" )
5230 .prepend( submenuCarat );
5231 menu.attr( "aria-labelledby", item.attr( "id" ) );
5234 menus = submenus.add( this.element );
5235 items = menus.find( this.options.items );
5237 // Initialize menu-items containing spaces and/or dashes only as dividers
5238 items.not( ".ui-menu-item" ).each(function() {
5239 var item = $( this );
5240 if ( that._isDivider( item ) ) {
5241 item.addClass( "ui-widget-content ui-menu-divider" );
5245 // Don't refresh list items that are already adapted
5246 items.not( ".ui-menu-item, .ui-menu-divider" )
5247 .addClass( "ui-menu-item" )
5251 role: this._itemRole()
5254 // Add aria-disabled attribute to any disabled menu item
5255 items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
5257 // If the active item has been removed, blur the menu
5258 if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
5263 _itemRole: function() {
5267 }[ this.options.role ];
5270 _setOption: function( key, value ) {
5271 if ( key === "icons" ) {
5272 this.element.find( ".ui-menu-icon" )
5273 .removeClass( this.options.icons.submenu )
5274 .addClass( value.submenu );
5276 if ( key === "disabled" ) {
5278 .toggleClass( "ui-state-disabled", !!value )
5279 .attr( "aria-disabled", value );
5281 this._super( key, value );
5284 focus: function( event, item ) {
5285 var nested, focused;
5286 this.blur( event, event && event.type === "focus" );
5288 this._scrollIntoView( item );
5290 this.active = item.first();
5291 focused = this.active.addClass( "ui-state-focus" ).removeClass( "ui-state-active" );
5292 // Only update aria-activedescendant if there's a role
5293 // otherwise we assume focus is managed elsewhere
5294 if ( this.options.role ) {
5295 this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
5298 // Highlight active parent menu item, if any
5301 .closest( ".ui-menu-item" )
5302 .addClass( "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.active.removeClass( "ui-state-focus" );
5351 this._trigger( "blur", event, { item: this.active } );
5354 _startOpening: function( submenu ) {
5355 clearTimeout( this.timer );
5357 // Don't open if already open fixes a Firefox bug that caused a .5 pixel
5358 // shift in the submenu position when mousing over the carat icon
5359 if ( submenu.attr( "aria-hidden" ) !== "true" ) {
5363 this.timer = this._delay(function() {
5365 this._open( submenu );
5369 _open: function( submenu ) {
5370 var position = $.extend({
5372 }, this.options.position );
5374 clearTimeout( this.timer );
5375 this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
5377 .attr( "aria-hidden", "true" );
5381 .removeAttr( "aria-hidden" )
5382 .attr( "aria-expanded", "true" )
5383 .position( position );
5386 collapseAll: function( event, all ) {
5387 clearTimeout( this.timer );
5388 this.timer = this._delay(function() {
5389 // If we were passed an event, look for the submenu that contains the event
5390 var currentMenu = all ? this.element :
5391 $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
5393 // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway
5394 if ( !currentMenu.length ) {
5395 currentMenu = this.element;
5398 this._close( currentMenu );
5401 this.activeMenu = currentMenu;
5405 // With no arguments, closes the currently active menu - if nothing is active
5406 // it closes all menus. If passed an argument, it will search for menus BELOW
5407 _close: function( startMenu ) {
5409 startMenu = this.active ? this.active.parent() : this.element;
5415 .attr( "aria-hidden", "true" )
5416 .attr( "aria-expanded", "false" )
5418 .find( ".ui-state-active" ).not( ".ui-state-focus" )
5419 .removeClass( "ui-state-active" );
5422 _closeOnDocumentClick: function( event ) {
5423 return !$( event.target ).closest( ".ui-menu" ).length;
5426 _isDivider: function( item ) {
5428 // Match hyphen, em dash, en dash
5429 return !/[^\-\u2014\u2013\s]/.test( item.text() );
5432 collapse: function( event ) {
5433 var newItem = this.active &&
5434 this.active.parent().closest( ".ui-menu-item", this.element );
5435 if ( newItem && newItem.length ) {
5437 this.focus( event, newItem );
5441 expand: function( event ) {
5442 var newItem = this.active &&
5444 .children( ".ui-menu " )
5445 .find( this.options.items )
5448 if ( newItem && newItem.length ) {
5449 this._open( newItem.parent() );
5451 // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
5452 this._delay(function() {
5453 this.focus( event, newItem );
5458 next: function( event ) {
5459 this._move( "next", "first", event );
5462 previous: function( event ) {
5463 this._move( "prev", "last", event );
5466 isFirstItem: function() {
5467 return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
5470 isLastItem: function() {
5471 return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
5474 _move: function( direction, filter, event ) {
5476 if ( this.active ) {
5477 if ( direction === "first" || direction === "last" ) {
5479 [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
5483 [ direction + "All" ]( ".ui-menu-item" )
5487 if ( !next || !next.length || !this.active ) {
5488 next = this.activeMenu.find( this.options.items )[ filter ]();
5491 this.focus( event, next );
5494 nextPage: function( event ) {
5495 var item, base, height;
5497 if ( !this.active ) {
5501 if ( this.isLastItem() ) {
5504 if ( this._hasScroll() ) {
5505 base = this.active.offset().top;
5506 height = this.element.height();
5507 this.active.nextAll( ".ui-menu-item" ).each(function() {
5509 return item.offset().top - base - height < 0;
5512 this.focus( event, item );
5514 this.focus( event, this.activeMenu.find( this.options.items )
5515 [ !this.active ? "first" : "last" ]() );
5519 previousPage: function( event ) {
5520 var item, base, height;
5521 if ( !this.active ) {
5525 if ( this.isFirstItem() ) {
5528 if ( this._hasScroll() ) {
5529 base = this.active.offset().top;
5530 height = this.element.height();
5531 this.active.prevAll( ".ui-menu-item" ).each(function() {
5533 return item.offset().top - base + height > 0;
5536 this.focus( event, item );
5538 this.focus( event, this.activeMenu.find( this.options.items ).first() );
5542 _hasScroll: function() {
5543 return this.element.outerHeight() < this.element.prop( "scrollHeight" );
5546 select: function( event ) {
5547 // TODO: It should never be possible to not have an active item at this
5548 // point, but the tests don't trigger mouseenter before click.
5549 this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
5550 var ui = { item: this.active };
5551 if ( !this.active.has( ".ui-menu" ).length ) {
5552 this.collapseAll( event, true );
5554 this._trigger( "select", event, ui );
5557 _filterMenuItems: function(character) {
5558 var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ),
5559 regex = new RegExp( "^" + escapedCharacter, "i" );
5561 return this.activeMenu
5562 .find( this.options.items )
5564 // Only match on items, not dividers or other content (#10571)
5565 .filter( ".ui-menu-item" )
5566 .filter(function() {
5567 return regex.test( $.trim( $( this ).text() ) );
5574 * jQuery UI Autocomplete 1.11.4
5575 * http://jqueryui.com
5577 * Copyright jQuery Foundation and other contributors
5578 * Released under the MIT license.
5579 * http://jquery.org/license
5581 * http://api.jqueryui.com/autocomplete/
5585 $.widget( "ui.autocomplete", {
5587 defaultElement: "<input>",
5613 _create: function() {
5614 // Some browsers only repeat keydown events, not keypress events,
5615 // so we use the suppressKeyPress flag to determine if we've already
5616 // handled the keydown event. #7269
5617 // Unfortunately the code for & in keypress is the same as the up arrow,
5618 // so we use the suppressKeyPressRepeat flag to avoid handling keypress
5619 // events when we know the keydown event was used to modify the
5620 // search term. #7799
5621 var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
5622 nodeName = this.element[ 0 ].nodeName.toLowerCase(),
5623 isTextarea = nodeName === "textarea",
5624 isInput = nodeName === "input";
5627 // Textareas are always multi-line
5629 // Inputs are always single-line, even if inside a contentEditable element
5630 // IE also treats inputs as contentEditable
5632 // All other element types are determined by whether or not they're contentEditable
5633 this.element.prop( "isContentEditable" );
5635 this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
5636 this.isNewMenu = true;
5639 .addClass( "ui-autocomplete-input" )
5640 .attr( "autocomplete", "off" );
5642 this._on( this.element, {
5643 keydown: function( event ) {
5644 if ( this.element.prop( "readOnly" ) ) {
5645 suppressKeyPress = true;
5646 suppressInput = true;
5647 suppressKeyPressRepeat = true;
5651 suppressKeyPress = false;
5652 suppressInput = false;
5653 suppressKeyPressRepeat = false;
5654 var keyCode = $.ui.keyCode;
5655 switch ( event.keyCode ) {
5656 case keyCode.PAGE_UP:
5657 suppressKeyPress = true;
5658 this._move( "previousPage", event );
5660 case keyCode.PAGE_DOWN:
5661 suppressKeyPress = true;
5662 this._move( "nextPage", event );
5665 suppressKeyPress = true;
5666 this._keyEvent( "previous", event );
5669 suppressKeyPress = true;
5670 this._keyEvent( "next", event );
5673 // when menu is open and has focus
5674 if ( this.menu.active ) {
5675 // #6055 - Opera still allows the keypress to occur
5676 // which causes forms to submit
5677 suppressKeyPress = true;
5678 event.preventDefault();
5679 this.menu.select( event );
5683 if ( this.menu.active ) {
5684 this.menu.select( event );
5687 case keyCode.ESCAPE:
5688 if ( this.menu.element.is( ":visible" ) ) {
5689 if ( !this.isMultiLine ) {
5690 this._value( this.term );
5692 this.close( event );
5693 // Different browsers have different default behavior for escape
5694 // Single press can mean undo or clear
5695 // Double press in IE means clear the whole form
5696 event.preventDefault();
5700 suppressKeyPressRepeat = true;
5701 // search timeout should be triggered before the input value is changed
5702 this._searchTimeout( event );
5706 keypress: function( event ) {
5707 if ( suppressKeyPress ) {
5708 suppressKeyPress = false;
5709 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
5710 event.preventDefault();
5714 if ( suppressKeyPressRepeat ) {
5718 // replicate some key handlers to allow them to repeat in Firefox and Opera
5719 var keyCode = $.ui.keyCode;
5720 switch ( event.keyCode ) {
5721 case keyCode.PAGE_UP:
5722 this._move( "previousPage", event );
5724 case keyCode.PAGE_DOWN:
5725 this._move( "nextPage", event );
5728 this._keyEvent( "previous", event );
5731 this._keyEvent( "next", event );
5735 input: function( event ) {
5736 if ( suppressInput ) {
5737 suppressInput = false;
5738 event.preventDefault();
5741 this._searchTimeout( event );
5744 this.selectedItem = null;
5745 this.previous = this._value();
5747 blur: function( event ) {
5748 if ( this.cancelBlur ) {
5749 delete this.cancelBlur;
5753 clearTimeout( this.searching );
5754 this.close( event );
5755 this._change( event );
5760 this.menu = $( "<ul>" )
5761 .addClass( "ui-autocomplete ui-front" )
5762 .appendTo( this._appendTo() )
5764 // disable ARIA support, the live region takes care of that
5768 .menu( "instance" );
5770 this._on( this.menu.element, {
5771 mousedown: function( event ) {
5772 // prevent moving focus out of the text field
5773 event.preventDefault();
5775 // IE doesn't prevent moving focus even with event.preventDefault()
5776 // so we set a flag to know when we should ignore the blur event
5777 this.cancelBlur = true;
5778 this._delay(function() {
5779 delete this.cancelBlur;
5782 // clicking on the scrollbar causes focus to shift to the body
5783 // but we can't detect a mouseup or a click immediately afterward
5784 // so we have to track the next mousedown and close the menu if
5785 // the user clicks somewhere outside of the autocomplete
5786 var menuElement = this.menu.element[ 0 ];
5787 if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
5788 this._delay(function() {
5790 this.document.one( "mousedown", function( event ) {
5791 if ( event.target !== that.element[ 0 ] &&
5792 event.target !== menuElement &&
5793 !$.contains( menuElement, event.target ) ) {
5800 menufocus: function( event, ui ) {
5803 // Prevent accidental activation of menu items in Firefox (#7024 #9118)
5804 if ( this.isNewMenu ) {
5805 this.isNewMenu = false;
5806 if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
5809 this.document.one( "mousemove", function() {
5810 $( event.target ).trigger( event.originalEvent );
5817 item = ui.item.data( "ui-autocomplete-item" );
5818 if ( false !== this._trigger( "focus", event, { item: item } ) ) {
5819 // use value to match what will end up in the input, if it was a key event
5820 if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
5821 this._value( item.value );
5825 // Announce the value in the liveRegion
5826 label = ui.item.attr( "aria-label" ) || item.value;
5827 if ( label && $.trim( label ).length ) {
5828 this.liveRegion.children().hide();
5829 $( "<div>" ).text( label ).appendTo( this.liveRegion );
5832 menuselect: function( event, ui ) {
5833 var item = ui.item.data( "ui-autocomplete-item" ),
5834 previous = this.previous;
5836 // only trigger when focus was lost (click on menu)
5837 if ( this.element[ 0 ] !== this.document[ 0 ].activeElement ) {
5838 this.element.focus();
5839 this.previous = previous;
5840 // #6109 - IE triggers two focus events and the second
5841 // is asynchronous, so we need to reset the previous
5842 // term synchronously and asynchronously :-(
5843 this._delay(function() {
5844 this.previous = previous;
5845 this.selectedItem = item;
5849 if ( false !== this._trigger( "select", event, { item: item } ) ) {
5850 this._value( item.value );
5852 // reset the term after the select event
5853 // this allows custom select handling to work properly
5854 this.term = this._value();
5856 this.close( event );
5857 this.selectedItem = item;
5861 this.liveRegion = $( "<span>", {
5863 "aria-live": "assertive",
5864 "aria-relevant": "additions"
5866 .addClass( "ui-helper-hidden-accessible" )
5867 .appendTo( this.document[ 0 ].body );
5869 // turning off autocomplete prevents the browser from remembering the
5870 // value when navigating through history, so we re-enable autocomplete
5871 // if the page is unloaded before the widget is destroyed. #7790
5872 this._on( this.window, {
5873 beforeunload: function() {
5874 this.element.removeAttr( "autocomplete" );
5879 _destroy: function() {
5880 clearTimeout( this.searching );
5882 .removeClass( "ui-autocomplete-input" )
5883 .removeAttr( "autocomplete" );
5884 this.menu.element.remove();
5885 this.liveRegion.remove();
5888 _setOption: function( key, value ) {
5889 this._super( key, value );
5890 if ( key === "source" ) {
5893 if ( key === "appendTo" ) {
5894 this.menu.element.appendTo( this._appendTo() );
5896 if ( key === "disabled" && value && this.xhr ) {
5901 _appendTo: function() {
5902 var element = this.options.appendTo;
5905 element = element.jquery || element.nodeType ?
5907 this.document.find( element ).eq( 0 );
5910 if ( !element || !element[ 0 ] ) {
5911 element = this.element.closest( ".ui-front" );
5914 if ( !element.length ) {
5915 element = this.document[ 0 ].body;
5921 _initSource: function() {
5924 if ( $.isArray( this.options.source ) ) {
5925 array = this.options.source;
5926 this.source = function( request, response ) {
5927 response( $.ui.autocomplete.filter( array, request.term ) );
5929 } else if ( typeof this.options.source === "string" ) {
5930 url = this.options.source;
5931 this.source = function( request, response ) {
5939 success: function( data ) {
5948 this.source = this.options.source;
5952 _searchTimeout: function( event ) {
5953 clearTimeout( this.searching );
5954 this.searching = this._delay(function() {
5956 // Search if the value has changed, or if the user retypes the same value (see #7434)
5957 var equalValues = this.term === this._value(),
5958 menuVisible = this.menu.element.is( ":visible" ),
5959 modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
5961 if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) {
5962 this.selectedItem = null;
5963 this.search( null, event );
5965 }, this.options.delay );
5968 search: function( value, event ) {
5969 value = value != null ? value : this._value();
5971 // always save the actual value, not the one passed as an argument
5972 this.term = this._value();
5974 if ( value.length < this.options.minLength ) {
5975 return this.close( event );
5978 if ( this._trigger( "search", event ) === false ) {
5982 return this._search( value );
5985 _search: function( value ) {
5987 this.element.addClass( "ui-autocomplete-loading" );
5988 this.cancelSearch = false;
5990 this.source( { term: value }, this._response() );
5993 _response: function() {
5994 var index = ++this.requestIndex;
5996 return $.proxy(function( content ) {
5997 if ( index === this.requestIndex ) {
5998 this.__response( content );
6002 if ( !this.pending ) {
6003 this.element.removeClass( "ui-autocomplete-loading" );
6008 __response: function( content ) {
6010 content = this._normalize( content );
6012 this._trigger( "response", null, { content: content } );
6013 if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
6014 this._suggest( content );
6015 this._trigger( "open" );
6017 // use ._close() instead of .close() so we don't cancel future searches
6022 close: function( event ) {
6023 this.cancelSearch = true;
6024 this._close( event );
6027 _close: function( event ) {
6028 if ( this.menu.element.is( ":visible" ) ) {
6029 this.menu.element.hide();
6031 this.isNewMenu = true;
6032 this._trigger( "close", event );
6036 _change: function( event ) {
6037 if ( this.previous !== this._value() ) {
6038 this._trigger( "change", event, { item: this.selectedItem } );
6042 _normalize: function( items ) {
6043 // assume all items have the right format when the first item is complete
6044 if ( items.length && items[ 0 ].label && items[ 0 ].value ) {
6047 return $.map( items, function( item ) {
6048 if ( typeof item === "string" ) {
6054 return $.extend( {}, item, {
6055 label: item.label || item.value,
6056 value: item.value || item.label
6061 _suggest: function( items ) {
6062 var ul = this.menu.element.empty();
6063 this._renderMenu( ul, items );
6064 this.isNewMenu = true;
6065 this.menu.refresh();
6067 // size and position menu
6070 ul.position( $.extend({
6072 }, this.options.position ) );
6074 if ( this.options.autoFocus ) {
6079 _resizeMenu: function() {
6080 var ul = this.menu.element;
6081 ul.outerWidth( Math.max(
6082 // Firefox wraps long text (possibly a rounding bug)
6083 // so we add 1px to avoid the wrapping (#7513)
6084 ul.width( "" ).outerWidth() + 1,
6085 this.element.outerWidth()
6089 _renderMenu: function( ul, items ) {
6091 $.each( items, function( index, item ) {
6092 that._renderItemData( ul, item );
6096 _renderItemData: function( ul, item ) {
6097 return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
6100 _renderItem: function( ul, item ) {
6101 return $( "<li>" ).text( item.label ).appendTo( ul );
6104 _move: function( direction, event ) {
6105 if ( !this.menu.element.is( ":visible" ) ) {
6106 this.search( null, event );
6109 if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
6110 this.menu.isLastItem() && /^next/.test( direction ) ) {
6112 if ( !this.isMultiLine ) {
6113 this._value( this.term );
6119 this.menu[ direction ]( event );
6122 widget: function() {
6123 return this.menu.element;
6126 _value: function() {
6127 return this.valueMethod.apply( this.element, arguments );
6130 _keyEvent: function( keyEvent, event ) {
6131 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
6132 this._move( keyEvent, event );
6134 // prevents moving cursor to beginning/end of the text field in some browsers
6135 event.preventDefault();
6140 $.extend( $.ui.autocomplete, {
6141 escapeRegex: function( value ) {
6142 return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
6144 filter: function( array, term ) {
6145 var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" );
6146 return $.grep( array, function( value ) {
6147 return matcher.test( value.label || value.value || value );
6152 // live region extension, adding a `messages` option
6153 // NOTE: This is an experimental API. We are still investigating
6154 // a full solution for string manipulation and internationalization.
6155 $.widget( "ui.autocomplete", $.ui.autocomplete, {
6158 noResults: "No search results.",
6159 results: function( amount ) {
6160 return amount + ( amount > 1 ? " results are" : " result is" ) +
6161 " available, use up and down arrow keys to navigate.";
6166 __response: function( content ) {
6168 this._superApply( arguments );
6169 if ( this.options.disabled || this.cancelSearch ) {
6172 if ( content && content.length ) {
6173 message = this.options.messages.results( content.length );
6175 message = this.options.messages.noResults;
6177 this.liveRegion.children().hide();
6178 $( "<div>" ).text( message ).appendTo( this.liveRegion );
6182 var autocomplete = $.ui.autocomplete;
6186 * jQuery UI Button 1.11.4
6187 * http://jqueryui.com
6189 * Copyright jQuery Foundation and other contributors
6190 * Released under the MIT license.
6191 * http://jquery.org/license
6193 * http://api.jqueryui.com/button/
6198 baseClasses = "ui-button ui-widget ui-state-default ui-corner-all",
6199 typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",
6200 formResetHandler = function() {
6201 var form = $( this );
6202 setTimeout(function() {
6203 form.find( ":ui-button" ).button( "refresh" );
6206 radioGroup = function( radio ) {
6207 var name = radio.name,
6211 name = name.replace( /'/g, "\\'" );
6213 radios = $( form ).find( "[name='" + name + "'][type=radio]" );
6215 radios = $( "[name='" + name + "'][type=radio]", radio.ownerDocument )
6216 .filter(function() {
6224 $.widget( "ui.button", {
6226 defaultElement: "<button>",
6236 _create: function() {
6237 this.element.closest( "form" )
6238 .unbind( "reset" + this.eventNamespace )
6239 .bind( "reset" + this.eventNamespace, formResetHandler );
6241 if ( typeof this.options.disabled !== "boolean" ) {
6242 this.options.disabled = !!this.element.prop( "disabled" );
6244 this.element.prop( "disabled", this.options.disabled );
6247 this._determineButtonType();
6248 this.hasTitle = !!this.buttonElement.attr( "title" );
6251 options = this.options,
6252 toggleButton = this.type === "checkbox" || this.type === "radio",
6253 activeClass = !toggleButton ? "ui-state-active" : "";
6255 if ( options.label === null ) {
6256 options.label = (this.type === "input" ? this.buttonElement.val() : this.buttonElement.html());
6259 this._hoverable( this.buttonElement );
6262 .addClass( baseClasses )
6263 .attr( "role", "button" )
6264 .bind( "mouseenter" + this.eventNamespace, function() {
6265 if ( options.disabled ) {
6268 if ( this === lastActive ) {
6269 $( this ).addClass( "ui-state-active" );
6272 .bind( "mouseleave" + this.eventNamespace, function() {
6273 if ( options.disabled ) {
6276 $( this ).removeClass( activeClass );
6278 .bind( "click" + this.eventNamespace, function( event ) {
6279 if ( options.disabled ) {
6280 event.preventDefault();
6281 event.stopImmediatePropagation();
6285 // Can't use _focusable() because the element that receives focus
6286 // and the element that gets the ui-state-focus class are different
6289 this.buttonElement.addClass( "ui-state-focus" );
6292 this.buttonElement.removeClass( "ui-state-focus" );
6296 if ( toggleButton ) {
6297 this.element.bind( "change" + this.eventNamespace, function() {
6302 if ( this.type === "checkbox" ) {
6303 this.buttonElement.bind( "click" + this.eventNamespace, function() {
6304 if ( options.disabled ) {
6308 } else if ( this.type === "radio" ) {
6309 this.buttonElement.bind( "click" + this.eventNamespace, function() {
6310 if ( options.disabled ) {
6313 $( this ).addClass( "ui-state-active" );
6314 that.buttonElement.attr( "aria-pressed", "true" );
6316 var radio = that.element[ 0 ];
6320 return $( this ).button( "widget" )[ 0 ];
6322 .removeClass( "ui-state-active" )
6323 .attr( "aria-pressed", "false" );
6327 .bind( "mousedown" + this.eventNamespace, function() {
6328 if ( options.disabled ) {
6331 $( this ).addClass( "ui-state-active" );
6333 that.document.one( "mouseup", function() {
6337 .bind( "mouseup" + this.eventNamespace, function() {
6338 if ( options.disabled ) {
6341 $( this ).removeClass( "ui-state-active" );
6343 .bind( "keydown" + this.eventNamespace, function(event) {
6344 if ( options.disabled ) {
6347 if ( event.keyCode === $.ui.keyCode.SPACE || event.keyCode === $.ui.keyCode.ENTER ) {
6348 $( this ).addClass( "ui-state-active" );
6351 // see #8559, we bind to blur here in case the button element loses
6352 // focus between keydown and keyup, it would be left in an "active" state
6353 .bind( "keyup" + this.eventNamespace + " blur" + this.eventNamespace, function() {
6354 $( this ).removeClass( "ui-state-active" );
6357 if ( this.buttonElement.is("a") ) {
6358 this.buttonElement.keyup(function(event) {
6359 if ( event.keyCode === $.ui.keyCode.SPACE ) {
6360 // TODO pass through original event correctly (just as 2nd argument doesn't work)
6367 this._setOption( "disabled", options.disabled );
6368 this._resetButton();
6371 _determineButtonType: function() {
6372 var ancestor, labelSelector, checked;
6374 if ( this.element.is("[type=checkbox]") ) {
6375 this.type = "checkbox";
6376 } else if ( this.element.is("[type=radio]") ) {
6377 this.type = "radio";
6378 } else if ( this.element.is("input") ) {
6379 this.type = "input";
6381 this.type = "button";
6384 if ( this.type === "checkbox" || this.type === "radio" ) {
6385 // we don't search against the document in case the element
6386 // is disconnected from the DOM
6387 ancestor = this.element.parents().last();
6388 labelSelector = "label[for='" + this.element.attr("id") + "']";
6389 this.buttonElement = ancestor.find( labelSelector );
6390 if ( !this.buttonElement.length ) {
6391 ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings();
6392 this.buttonElement = ancestor.filter( labelSelector );
6393 if ( !this.buttonElement.length ) {
6394 this.buttonElement = ancestor.find( labelSelector );
6397 this.element.addClass( "ui-helper-hidden-accessible" );
6399 checked = this.element.is( ":checked" );
6401 this.buttonElement.addClass( "ui-state-active" );
6403 this.buttonElement.prop( "aria-pressed", checked );
6405 this.buttonElement = this.element;
6409 widget: function() {
6410 return this.buttonElement;
6413 _destroy: function() {
6415 .removeClass( "ui-helper-hidden-accessible" );
6417 .removeClass( baseClasses + " ui-state-active " + typeClasses )
6418 .removeAttr( "role" )
6419 .removeAttr( "aria-pressed" )
6420 .html( this.buttonElement.find(".ui-button-text").html() );
6422 if ( !this.hasTitle ) {
6423 this.buttonElement.removeAttr( "title" );
6427 _setOption: function( key, value ) {
6428 this._super( key, value );
6429 if ( key === "disabled" ) {
6430 this.widget().toggleClass( "ui-state-disabled", !!value );
6431 this.element.prop( "disabled", !!value );
6433 if ( this.type === "checkbox" || this.type === "radio" ) {
6434 this.buttonElement.removeClass( "ui-state-focus" );
6436 this.buttonElement.removeClass( "ui-state-focus ui-state-active" );
6441 this._resetButton();
6444 refresh: function() {
6446 var isDisabled = this.element.is( "input, button" ) ? this.element.is( ":disabled" ) : this.element.hasClass( "ui-button-disabled" );
6448 if ( isDisabled !== this.options.disabled ) {
6449 this._setOption( "disabled", isDisabled );
6451 if ( this.type === "radio" ) {
6452 radioGroup( this.element[0] ).each(function() {
6453 if ( $( this ).is( ":checked" ) ) {
6454 $( this ).button( "widget" )
6455 .addClass( "ui-state-active" )
6456 .attr( "aria-pressed", "true" );
6458 $( this ).button( "widget" )
6459 .removeClass( "ui-state-active" )
6460 .attr( "aria-pressed", "false" );
6463 } else if ( this.type === "checkbox" ) {
6464 if ( this.element.is( ":checked" ) ) {
6466 .addClass( "ui-state-active" )
6467 .attr( "aria-pressed", "true" );
6470 .removeClass( "ui-state-active" )
6471 .attr( "aria-pressed", "false" );
6476 _resetButton: function() {
6477 if ( this.type === "input" ) {
6478 if ( this.options.label ) {
6479 this.element.val( this.options.label );
6483 var buttonElement = this.buttonElement.removeClass( typeClasses ),
6484 buttonText = $( "<span></span>", this.document[0] )
6485 .addClass( "ui-button-text" )
6486 .html( this.options.label )
6487 .appendTo( buttonElement.empty() )
6489 icons = this.options.icons,
6490 multipleIcons = icons.primary && icons.secondary,
6493 if ( icons.primary || icons.secondary ) {
6494 if ( this.options.text ) {
6495 buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) );
6498 if ( icons.primary ) {
6499 buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" );
6502 if ( icons.secondary ) {
6503 buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" );
6506 if ( !this.options.text ) {
6507 buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" );
6509 if ( !this.hasTitle ) {
6510 buttonElement.attr( "title", $.trim( buttonText ) );
6514 buttonClasses.push( "ui-button-text-only" );
6516 buttonElement.addClass( buttonClasses.join( " " ) );
6520 $.widget( "ui.buttonset", {
6523 items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)"
6526 _create: function() {
6527 this.element.addClass( "ui-buttonset" );
6534 _setOption: function( key, value ) {
6535 if ( key === "disabled" ) {
6536 this.buttons.button( "option", key, value );
6539 this._super( key, value );
6542 refresh: function() {
6543 var rtl = this.element.css( "direction" ) === "rtl",
6544 allButtons = this.element.find( this.options.items ),
6545 existingButtons = allButtons.filter( ":ui-button" );
6547 // Initialize new buttons
6548 allButtons.not( ":ui-button" ).button();
6550 // Refresh existing buttons
6551 existingButtons.button( "refresh" );
6553 this.buttons = allButtons
6555 return $( this ).button( "widget" )[ 0 ];
6557 .removeClass( "ui-corner-all ui-corner-left ui-corner-right" )
6559 .addClass( rtl ? "ui-corner-right" : "ui-corner-left" )
6562 .addClass( rtl ? "ui-corner-left" : "ui-corner-right" )
6567 _destroy: function() {
6568 this.element.removeClass( "ui-buttonset" );
6571 return $( this ).button( "widget" )[ 0 ];
6573 .removeClass( "ui-corner-left ui-corner-right" )
6575 .button( "destroy" );
6579 var button = $.ui.button;
6583 * jQuery UI Datepicker 1.11.4
6584 * http://jqueryui.com
6586 * Copyright jQuery Foundation and other contributors
6587 * Released under the MIT license.
6588 * http://jquery.org/license
6590 * http://api.jqueryui.com/datepicker/
6594 $.extend($.ui, { datepicker: { version: "1.11.4" } });
6596 var datepicker_instActive;
6598 function datepicker_getZindex( elem ) {
6599 var position, value;
6600 while ( elem.length && elem[ 0 ] !== document ) {
6601 // Ignore z-index if position is set to a value where z-index is ignored by the browser
6602 // This makes behavior of this function consistent across browsers
6603 // WebKit always returns auto if the element is positioned
6604 position = elem.css( "position" );
6605 if ( position === "absolute" || position === "relative" || position === "fixed" ) {
6606 // IE returns 0 when zIndex is not specified
6607 // other browsers return a string
6608 // we ignore the case of nested elements with an explicit value of 0
6609 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
6610 value = parseInt( elem.css( "zIndex" ), 10 );
6611 if ( !isNaN( value ) && value !== 0 ) {
6615 elem = elem.parent();
6620 /* Date picker manager.
6621 Use the singleton instance of this class, $.datepicker, to interact with the date picker.
6622 Settings for (groups of) date pickers are maintained in an instance object,
6623 allowing multiple different settings on the same page. */
6625 function Datepicker() {
6626 this._curInst = null; // The current instance in use
6627 this._keyEvent = false; // If the last event was a key event
6628 this._disabledInputs = []; // List of date picker inputs that have been disabled
6629 this._datepickerShowing = false; // True if the popup picker is showing , false if not
6630 this._inDialog = false; // True if showing within a "dialog", false if not
6631 this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
6632 this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
6633 this._appendClass = "ui-datepicker-append"; // The name of the append marker class
6634 this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
6635 this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
6636 this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
6637 this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
6638 this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
6639 this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
6640 this.regional = []; // Available regional settings, indexed by language code
6641 this.regional[""] = { // Default regional settings
6642 closeText: "Done", // Display text for close link
6643 prevText: "Prev", // Display text for previous month link
6644 nextText: "Next", // Display text for next month link
6645 currentText: "Today", // Display text for current month link
6646 monthNames: ["January","February","March","April","May","June",
6647 "July","August","September","October","November","December"], // Names of months for drop-down and formatting
6648 monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting
6649 dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting
6650 dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting
6651 dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday
6652 weekHeader: "Wk", // Column header for week of the year
6653 dateFormat: "mm/dd/yy", // See format options on parseDate
6654 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
6655 isRTL: false, // True if right-to-left language, false if left-to-right
6656 showMonthAfterYear: false, // True if the year select precedes month, false for month then year
6657 yearSuffix: "" // Additional text to append to the year in the month headers
6659 this._defaults = { // Global defaults for all the date picker instances
6660 showOn: "focus", // "focus" for popup on focus,
6661 // "button" for trigger button, or "both" for either
6662 showAnim: "fadeIn", // Name of jQuery animation for popup
6663 showOptions: {}, // Options for enhanced animations
6664 defaultDate: null, // Used when field is blank: actual date,
6665 // +/-number for offset from today, null for today
6666 appendText: "", // Display text following the input box, e.g. showing the format
6667 buttonText: "...", // Text for trigger button
6668 buttonImage: "", // URL for trigger button image
6669 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
6670 hideIfNoPrevNext: false, // True to hide next/previous month links
6671 // if not applicable, false to just disable them
6672 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
6673 gotoCurrent: false, // True if today link goes back to current selection instead
6674 changeMonth: false, // True if month can be selected directly, false if only prev/next
6675 changeYear: false, // True if year can be selected directly, false if only prev/next
6676 yearRange: "c-10:c+10", // Range of years to display in drop-down,
6677 // either relative to today's year (-nn:+nn), relative to currently displayed year
6678 // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
6679 showOtherMonths: false, // True to show dates in other months, false to leave blank
6680 selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
6681 showWeek: false, // True to show week of the year, false to not show it
6682 calculateWeek: this.iso8601Week, // How to calculate the week of the year,
6683 // takes a Date and returns the number of the week for it
6684 shortYearCutoff: "+10", // Short year values < this are in the current century,
6685 // > this are in the previous century,
6686 // string value starting with "+" for current year + value
6687 minDate: null, // The earliest selectable date, or null for no limit
6688 maxDate: null, // The latest selectable date, or null for no limit
6689 duration: "fast", // Duration of display/closure
6690 beforeShowDay: null, // Function that takes a date and returns an array with
6691 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
6692 // [2] = cell title (optional), e.g. $.datepicker.noWeekends
6693 beforeShow: null, // Function that takes an input field and
6694 // returns a set of custom settings for the date picker
6695 onSelect: null, // Define a callback function when a date is selected
6696 onChangeMonthYear: null, // Define a callback function when the month or year is changed
6697 onClose: null, // Define a callback function when the datepicker is closed
6698 numberOfMonths: 1, // Number of months to show at a time
6699 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
6700 stepMonths: 1, // Number of months to step back/forward
6701 stepBigMonths: 12, // Number of months to step back/forward for the big links
6702 altField: "", // Selector for an alternate field to store selected dates into
6703 altFormat: "", // The date format to use for the alternate field
6704 constrainInput: true, // The input is constrained by the current date format
6705 showButtonPanel: false, // True to show button panel, false to not show it
6706 autoSize: false, // True to size the input for the date format, false to leave as is
6707 disabled: false // The initial disabled state
6709 $.extend(this._defaults, this.regional[""]);
6710 this.regional.en = $.extend( true, {}, this.regional[ "" ]);
6711 this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en );
6712 this.dpDiv = datepicker_bindHover($("<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"));
6715 $.extend(Datepicker.prototype, {
6716 /* Class name added to elements to indicate already configured with a date picker. */
6717 markerClassName: "hasDatepicker",
6719 //Keep track of the maximum number of rows displayed (see #7043)
6722 // TODO rename to "widget" when switching to widget factory
6723 _widgetDatepicker: function() {
6727 /* Override the default settings for all instances of the date picker.
6728 * @param settings object - the new settings to use as defaults (anonymous object)
6729 * @return the manager object
6731 setDefaults: function(settings) {
6732 datepicker_extendRemove(this._defaults, settings || {});
6736 /* Attach the date picker to a jQuery selection.
6737 * @param target element - the target input field or division or span
6738 * @param settings object - the new settings to use for this date picker instance (anonymous)
6740 _attachDatepicker: function(target, settings) {
6741 var nodeName, inline, inst;
6742 nodeName = target.nodeName.toLowerCase();
6743 inline = (nodeName === "div" || nodeName === "span");
6746 target.id = "dp" + this.uuid;
6748 inst = this._newInst($(target), inline);
6749 inst.settings = $.extend({}, settings || {});
6750 if (nodeName === "input") {
6751 this._connectDatepicker(target, inst);
6752 } else if (inline) {
6753 this._inlineDatepicker(target, inst);
6757 /* Create a new instance object. */
6758 _newInst: function(target, inline) {
6759 var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars
6760 return {id: id, input: target, // associated target
6761 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
6762 drawMonth: 0, drawYear: 0, // month being drawn
6763 inline: inline, // is datepicker inline or not
6764 dpDiv: (!inline ? this.dpDiv : // presentation div
6765 datepicker_bindHover($("<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))};
6768 /* Attach the date picker to an input field. */
6769 _connectDatepicker: function(target, inst) {
6770 var input = $(target);
6771 inst.append = $([]);
6772 inst.trigger = $([]);
6773 if (input.hasClass(this.markerClassName)) {
6776 this._attachments(input, inst);
6777 input.addClass(this.markerClassName).keydown(this._doKeyDown).
6778 keypress(this._doKeyPress).keyup(this._doKeyUp);
6779 this._autoSize(inst);
6780 $.data(target, "datepicker", inst);
6781 //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
6782 if( inst.settings.disabled ) {
6783 this._disableDatepicker( target );
6787 /* Make attachments based on settings. */
6788 _attachments: function(input, inst) {
6789 var showOn, buttonText, buttonImage,
6790 appendText = this._get(inst, "appendText"),
6791 isRTL = this._get(inst, "isRTL");
6794 inst.append.remove();
6797 inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>");
6798 input[isRTL ? "before" : "after"](inst.append);
6801 input.unbind("focus", this._showDatepicker);
6804 inst.trigger.remove();
6807 showOn = this._get(inst, "showOn");
6808 if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field
6809 input.focus(this._showDatepicker);
6811 if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked
6812 buttonText = this._get(inst, "buttonText");
6813 buttonImage = this._get(inst, "buttonImage");
6814 inst.trigger = $(this._get(inst, "buttonImageOnly") ?
6815 $("<img/>").addClass(this._triggerClass).
6816 attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
6817 $("<button type='button'></button>").addClass(this._triggerClass).
6818 html(!buttonImage ? buttonText : $("<img/>").attr(
6819 { src:buttonImage, alt:buttonText, title:buttonText })));
6820 input[isRTL ? "before" : "after"](inst.trigger);
6821 inst.trigger.click(function() {
6822 if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) {
6823 $.datepicker._hideDatepicker();
6824 } else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) {
6825 $.datepicker._hideDatepicker();
6826 $.datepicker._showDatepicker(input[0]);
6828 $.datepicker._showDatepicker(input[0]);
6835 /* Apply the maximum length for the date format. */
6836 _autoSize: function(inst) {
6837 if (this._get(inst, "autoSize") && !inst.inline) {
6838 var findMax, max, maxI, i,
6839 date = new Date(2009, 12 - 1, 20), // Ensure double digits
6840 dateFormat = this._get(inst, "dateFormat");
6842 if (dateFormat.match(/[DM]/)) {
6843 findMax = function(names) {
6846 for (i = 0; i < names.length; i++) {
6847 if (names[i].length > max) {
6848 max = names[i].length;
6854 date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
6855 "monthNames" : "monthNamesShort"))));
6856 date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
6857 "dayNames" : "dayNamesShort"))) + 20 - date.getDay());
6859 inst.input.attr("size", this._formatDate(inst, date).length);
6863 /* Attach an inline date picker to a div. */
6864 _inlineDatepicker: function(target, inst) {
6865 var divSpan = $(target);
6866 if (divSpan.hasClass(this.markerClassName)) {
6869 divSpan.addClass(this.markerClassName).append(inst.dpDiv);
6870 $.data(target, "datepicker", inst);
6871 this._setDate(inst, this._getDefaultDate(inst), true);
6872 this._updateDatepicker(inst);
6873 this._updateAlternate(inst);
6874 //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
6875 if( inst.settings.disabled ) {
6876 this._disableDatepicker( target );
6878 // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
6879 // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
6880 inst.dpDiv.css( "display", "block" );
6883 /* Pop-up the date picker in a "dialog" box.
6884 * @param input element - ignored
6885 * @param date string or Date - the initial date to display
6886 * @param onSelect function - the function to call when a date is selected
6887 * @param settings object - update the dialog date picker instance's settings (anonymous object)
6888 * @param pos int[2] - coordinates for the dialog's position within the screen or
6889 * event - with x/y coordinates or
6890 * leave empty for default (screen centre)
6891 * @return the manager object
6893 _dialogDatepicker: function(input, date, onSelect, settings, pos) {
6894 var id, browserWidth, browserHeight, scrollX, scrollY,
6895 inst = this._dialogInst; // internal instance
6899 id = "dp" + this.uuid;
6900 this._dialogInput = $("<input type='text' id='" + id +
6901 "' style='position: absolute; top: -100px; width: 0px;'/>");
6902 this._dialogInput.keydown(this._doKeyDown);
6903 $("body").append(this._dialogInput);
6904 inst = this._dialogInst = this._newInst(this._dialogInput, false);
6906 $.data(this._dialogInput[0], "datepicker", inst);
6908 datepicker_extendRemove(inst.settings, settings || {});
6909 date = (date && date.constructor === Date ? this._formatDate(inst, date) : date);
6910 this._dialogInput.val(date);
6912 this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
6914 browserWidth = document.documentElement.clientWidth;
6915 browserHeight = document.documentElement.clientHeight;
6916 scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
6917 scrollY = document.documentElement.scrollTop || document.body.scrollTop;
6918 this._pos = // should use actual width/height below
6919 [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
6922 // move input on screen for focus, but hidden behind dialog
6923 this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px");
6924 inst.settings.onSelect = onSelect;
6925 this._inDialog = true;
6926 this.dpDiv.addClass(this._dialogClass);
6927 this._showDatepicker(this._dialogInput[0]);
6929 $.blockUI(this.dpDiv);
6931 $.data(this._dialogInput[0], "datepicker", inst);
6935 /* Detach a datepicker from its control.
6936 * @param target element - the target input field or division or span
6938 _destroyDatepicker: function(target) {
6940 $target = $(target),
6941 inst = $.data(target, "datepicker");
6943 if (!$target.hasClass(this.markerClassName)) {
6947 nodeName = target.nodeName.toLowerCase();
6948 $.removeData(target, "datepicker");
6949 if (nodeName === "input") {
6950 inst.append.remove();
6951 inst.trigger.remove();
6952 $target.removeClass(this.markerClassName).
6953 unbind("focus", this._showDatepicker).
6954 unbind("keydown", this._doKeyDown).
6955 unbind("keypress", this._doKeyPress).
6956 unbind("keyup", this._doKeyUp);
6957 } else if (nodeName === "div" || nodeName === "span") {
6958 $target.removeClass(this.markerClassName).empty();
6961 if ( datepicker_instActive === inst ) {
6962 datepicker_instActive = null;
6966 /* Enable the date picker to a jQuery selection.
6967 * @param target element - the target input field or division or span
6969 _enableDatepicker: function(target) {
6970 var nodeName, inline,
6971 $target = $(target),
6972 inst = $.data(target, "datepicker");
6974 if (!$target.hasClass(this.markerClassName)) {
6978 nodeName = target.nodeName.toLowerCase();
6979 if (nodeName === "input") {
6980 target.disabled = false;
6981 inst.trigger.filter("button").
6982 each(function() { this.disabled = false; }).end().
6983 filter("img").css({opacity: "1.0", cursor: ""});
6984 } else if (nodeName === "div" || nodeName === "span") {
6985 inline = $target.children("." + this._inlineClass);
6986 inline.children().removeClass("ui-state-disabled");
6987 inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
6988 prop("disabled", false);
6990 this._disabledInputs = $.map(this._disabledInputs,
6991 function(value) { return (value === target ? null : value); }); // delete entry
6994 /* Disable the date picker to a jQuery selection.
6995 * @param target element - the target input field or division or span
6997 _disableDatepicker: function(target) {
6998 var nodeName, inline,
6999 $target = $(target),
7000 inst = $.data(target, "datepicker");
7002 if (!$target.hasClass(this.markerClassName)) {
7006 nodeName = target.nodeName.toLowerCase();
7007 if (nodeName === "input") {
7008 target.disabled = true;
7009 inst.trigger.filter("button").
7010 each(function() { this.disabled = true; }).end().
7011 filter("img").css({opacity: "0.5", cursor: "default"});
7012 } else if (nodeName === "div" || nodeName === "span") {
7013 inline = $target.children("." + this._inlineClass);
7014 inline.children().addClass("ui-state-disabled");
7015 inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
7016 prop("disabled", true);
7018 this._disabledInputs = $.map(this._disabledInputs,
7019 function(value) { return (value === target ? null : value); }); // delete entry
7020 this._disabledInputs[this._disabledInputs.length] = target;
7023 /* Is the first field in a jQuery collection disabled as a datepicker?
7024 * @param target element - the target input field or division or span
7025 * @return boolean - true if disabled, false if enabled
7027 _isDisabledDatepicker: function(target) {
7031 for (var i = 0; i < this._disabledInputs.length; i++) {
7032 if (this._disabledInputs[i] === target) {
7039 /* Retrieve the instance data for the target control.
7040 * @param target element - the target input field or division or span
7041 * @return object - the associated instance data
7042 * @throws error if a jQuery problem getting data
7044 _getInst: function(target) {
7046 return $.data(target, "datepicker");
7049 throw "Missing instance data for this datepicker";
7053 /* Update or retrieve the settings for a date picker attached to an input field or division.
7054 * @param target element - the target input field or division or span
7055 * @param name object - the new settings to update or
7056 * string - the name of the setting to change or retrieve,
7057 * when retrieving also "all" for all instance settings or
7058 * "defaults" for all global defaults
7059 * @param value any - the new value for the setting
7060 * (omit if above is an object or to retrieve a value)
7062 _optionDatepicker: function(target, name, value) {
7063 var settings, date, minDate, maxDate,
7064 inst = this._getInst(target);
7066 if (arguments.length === 2 && typeof name === "string") {
7067 return (name === "defaults" ? $.extend({}, $.datepicker._defaults) :
7068 (inst ? (name === "all" ? $.extend({}, inst.settings) :
7069 this._get(inst, name)) : null));
7072 settings = name || {};
7073 if (typeof name === "string") {
7075 settings[name] = value;
7079 if (this._curInst === inst) {
7080 this._hideDatepicker();
7083 date = this._getDateDatepicker(target, true);
7084 minDate = this._getMinMaxDate(inst, "min");
7085 maxDate = this._getMinMaxDate(inst, "max");
7086 datepicker_extendRemove(inst.settings, settings);
7087 // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
7088 if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) {
7089 inst.settings.minDate = this._formatDate(inst, minDate);
7091 if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) {
7092 inst.settings.maxDate = this._formatDate(inst, maxDate);
7094 if ( "disabled" in settings ) {
7095 if ( settings.disabled ) {
7096 this._disableDatepicker(target);
7098 this._enableDatepicker(target);
7101 this._attachments($(target), inst);
7102 this._autoSize(inst);
7103 this._setDate(inst, date);
7104 this._updateAlternate(inst);
7105 this._updateDatepicker(inst);
7109 // change method deprecated
7110 _changeDatepicker: function(target, name, value) {
7111 this._optionDatepicker(target, name, value);
7114 /* Redraw the date picker attached to an input field or division.
7115 * @param target element - the target input field or division or span
7117 _refreshDatepicker: function(target) {
7118 var inst = this._getInst(target);
7120 this._updateDatepicker(inst);
7124 /* Set the dates for a jQuery selection.
7125 * @param target element - the target input field or division or span
7126 * @param date Date - the new date
7128 _setDateDatepicker: function(target, date) {
7129 var inst = this._getInst(target);
7131 this._setDate(inst, date);
7132 this._updateDatepicker(inst);
7133 this._updateAlternate(inst);
7137 /* Get the date(s) for the first entry in a jQuery selection.
7138 * @param target element - the target input field or division or span
7139 * @param noDefault boolean - true if no default date is to be used
7140 * @return Date - the current date
7142 _getDateDatepicker: function(target, noDefault) {
7143 var inst = this._getInst(target);
7144 if (inst && !inst.inline) {
7145 this._setDateFromField(inst, noDefault);
7147 return (inst ? this._getDate(inst) : null);
7150 /* Handle keystrokes. */
7151 _doKeyDown: function(event) {
7152 var onSelect, dateStr, sel,
7153 inst = $.datepicker._getInst(event.target),
7155 isRTL = inst.dpDiv.is(".ui-datepicker-rtl");
7157 inst._keyEvent = true;
7158 if ($.datepicker._datepickerShowing) {
7159 switch (event.keyCode) {
7160 case 9: $.datepicker._hideDatepicker();
7162 break; // hide on tab out
7163 case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." +
7164 $.datepicker._currentClass + ")", inst.dpDiv);
7166 $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
7169 onSelect = $.datepicker._get(inst, "onSelect");
7171 dateStr = $.datepicker._formatDate(inst);
7173 // trigger custom callback
7174 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);
7176 $.datepicker._hideDatepicker();
7179 return false; // don't submit the form
7180 case 27: $.datepicker._hideDatepicker();
7181 break; // hide on escape
7182 case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
7183 -$.datepicker._get(inst, "stepBigMonths") :
7184 -$.datepicker._get(inst, "stepMonths")), "M");
7185 break; // previous month/year on page up/+ ctrl
7186 case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
7187 +$.datepicker._get(inst, "stepBigMonths") :
7188 +$.datepicker._get(inst, "stepMonths")), "M");
7189 break; // next month/year on page down/+ ctrl
7190 case 35: if (event.ctrlKey || event.metaKey) {
7191 $.datepicker._clearDate(event.target);
7193 handled = event.ctrlKey || event.metaKey;
7194 break; // clear on ctrl or command +end
7195 case 36: if (event.ctrlKey || event.metaKey) {
7196 $.datepicker._gotoToday(event.target);
7198 handled = event.ctrlKey || event.metaKey;
7199 break; // current on ctrl or command +home
7200 case 37: if (event.ctrlKey || event.metaKey) {
7201 $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D");
7203 handled = event.ctrlKey || event.metaKey;
7204 // -1 day on ctrl or command +left
7205 if (event.originalEvent.altKey) {
7206 $.datepicker._adjustDate(event.target, (event.ctrlKey ?
7207 -$.datepicker._get(inst, "stepBigMonths") :
7208 -$.datepicker._get(inst, "stepMonths")), "M");
7210 // next month/year on alt +left on Mac
7212 case 38: if (event.ctrlKey || event.metaKey) {
7213 $.datepicker._adjustDate(event.target, -7, "D");
7215 handled = event.ctrlKey || event.metaKey;
7216 break; // -1 week on ctrl or command +up
7217 case 39: if (event.ctrlKey || event.metaKey) {
7218 $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D");
7220 handled = event.ctrlKey || event.metaKey;
7221 // +1 day on ctrl or command +right
7222 if (event.originalEvent.altKey) {
7223 $.datepicker._adjustDate(event.target, (event.ctrlKey ?
7224 +$.datepicker._get(inst, "stepBigMonths") :
7225 +$.datepicker._get(inst, "stepMonths")), "M");
7227 // next month/year on alt +right
7229 case 40: if (event.ctrlKey || event.metaKey) {
7230 $.datepicker._adjustDate(event.target, +7, "D");
7232 handled = event.ctrlKey || event.metaKey;
7233 break; // +1 week on ctrl or command +down
7234 default: handled = false;
7236 } else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home
7237 $.datepicker._showDatepicker(this);
7243 event.preventDefault();
7244 event.stopPropagation();
7248 /* Filter entered characters - based on date format. */
7249 _doKeyPress: function(event) {
7251 inst = $.datepicker._getInst(event.target);
7253 if ($.datepicker._get(inst, "constrainInput")) {
7254 chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat"));
7255 chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode);
7256 return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1);
7260 /* Synchronise manual entry and field/alternate field. */
7261 _doKeyUp: function(event) {
7263 inst = $.datepicker._getInst(event.target);
7265 if (inst.input.val() !== inst.lastVal) {
7267 date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
7268 (inst.input ? inst.input.val() : null),
7269 $.datepicker._getFormatConfig(inst));
7271 if (date) { // only if valid
7272 $.datepicker._setDateFromField(inst);
7273 $.datepicker._updateAlternate(inst);
7274 $.datepicker._updateDatepicker(inst);
7283 /* Pop-up the date picker for a given input field.
7284 * If false returned from beforeShow event handler do not show.
7285 * @param input element - the input field attached to the date picker or
7286 * event - if triggered by focus
7288 _showDatepicker: function(input) {
7289 input = input.target || input;
7290 if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger
7291 input = $("input", input.parentNode)[0];
7294 if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here
7298 var inst, beforeShow, beforeShowSettings, isFixed,
7299 offset, showAnim, duration;
7301 inst = $.datepicker._getInst(input);
7302 if ($.datepicker._curInst && $.datepicker._curInst !== inst) {
7303 $.datepicker._curInst.dpDiv.stop(true, true);
7304 if ( inst && $.datepicker._datepickerShowing ) {
7305 $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );
7309 beforeShow = $.datepicker._get(inst, "beforeShow");
7310 beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
7311 if(beforeShowSettings === false){
7314 datepicker_extendRemove(inst.settings, beforeShowSettings);
7316 inst.lastVal = null;
7317 $.datepicker._lastInput = input;
7318 $.datepicker._setDateFromField(inst);
7320 if ($.datepicker._inDialog) { // hide cursor
7323 if (!$.datepicker._pos) { // position below input
7324 $.datepicker._pos = $.datepicker._findPos(input);
7325 $.datepicker._pos[1] += input.offsetHeight; // add the height
7329 $(input).parents().each(function() {
7330 isFixed |= $(this).css("position") === "fixed";
7334 offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
7335 $.datepicker._pos = null;
7336 //to avoid flashes on Firefox
7338 // determine sizing offscreen
7339 inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"});
7340 $.datepicker._updateDatepicker(inst);
7341 // fix width for dynamic number of date pickers
7342 // and adjust position before showing
7343 offset = $.datepicker._checkOffset(inst, offset, isFixed);
7344 inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
7345 "static" : (isFixed ? "fixed" : "absolute")), display: "none",
7346 left: offset.left + "px", top: offset.top + "px"});
7349 showAnim = $.datepicker._get(inst, "showAnim");
7350 duration = $.datepicker._get(inst, "duration");
7351 inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 );
7352 $.datepicker._datepickerShowing = true;
7354 if ( $.effects && $.effects.effect[ showAnim ] ) {
7355 inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration);
7357 inst.dpDiv[showAnim || "show"](showAnim ? duration : null);
7360 if ( $.datepicker._shouldFocusInput( inst ) ) {
7364 $.datepicker._curInst = inst;
7368 /* Generate the date picker content. */
7369 _updateDatepicker: function(inst) {
7370 this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
7371 datepicker_instActive = inst; // for delegate hover events
7372 inst.dpDiv.empty().append(this._generateHTML(inst));
7373 this._attachHandlers(inst);
7376 numMonths = this._getNumberOfMonths(inst),
7377 cols = numMonths[1],
7379 activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" );
7381 if ( activeCell.length > 0 ) {
7382 datepicker_handleMouseover.apply( activeCell.get( 0 ) );
7385 inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");
7387 inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em");
7389 inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") +
7390 "Class"]("ui-datepicker-multi");
7391 inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") +
7392 "Class"]("ui-datepicker-rtl");
7394 if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
7398 // deffered render of the years select (to avoid flashes on Firefox)
7399 if( inst.yearshtml ){
7400 origyearshtml = inst.yearshtml;
7401 setTimeout(function(){
7402 //assure that inst.yearshtml didn't change.
7403 if( origyearshtml === inst.yearshtml && inst.yearshtml ){
7404 inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml);
7406 origyearshtml = inst.yearshtml = null;
7411 // #6694 - don't focus the input if it's already focused
7412 // this breaks the change event in IE
7413 // Support: IE and jQuery <1.9
7414 _shouldFocusInput: function( inst ) {
7415 return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
7418 /* Check positioning to remain on screen. */
7419 _checkOffset: function(inst, offset, isFixed) {
7420 var dpWidth = inst.dpDiv.outerWidth(),
7421 dpHeight = inst.dpDiv.outerHeight(),
7422 inputWidth = inst.input ? inst.input.outerWidth() : 0,
7423 inputHeight = inst.input ? inst.input.outerHeight() : 0,
7424 viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()),
7425 viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop());
7427 offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0);
7428 offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0;
7429 offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
7431 // now check if datepicker is showing outside window viewport - move to a better place if so.
7432 offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
7433 Math.abs(offset.left + dpWidth - viewWidth) : 0);
7434 offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
7435 Math.abs(dpHeight + inputHeight) : 0);
7440 /* Find an object's position on the screen. */
7441 _findPos: function(obj) {
7443 inst = this._getInst(obj),
7444 isRTL = this._get(inst, "isRTL");
7446 while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) {
7447 obj = obj[isRTL ? "previousSibling" : "nextSibling"];
7450 position = $(obj).offset();
7451 return [position.left, position.top];
7454 /* Hide the date picker from view.
7455 * @param input element - the input field attached to the date picker
7457 _hideDatepicker: function(input) {
7458 var showAnim, duration, postProcess, onClose,
7459 inst = this._curInst;
7461 if (!inst || (input && inst !== $.data(input, "datepicker"))) {
7465 if (this._datepickerShowing) {
7466 showAnim = this._get(inst, "showAnim");
7467 duration = this._get(inst, "duration");
7468 postProcess = function() {
7469 $.datepicker._tidyDialog(inst);
7472 // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
7473 if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
7474 inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess);
7476 inst.dpDiv[(showAnim === "slideDown" ? "slideUp" :
7477 (showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess);
7483 this._datepickerShowing = false;
7485 onClose = this._get(inst, "onClose");
7487 onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]);
7490 this._lastInput = null;
7491 if (this._inDialog) {
7492 this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" });
7495 $("body").append(this.dpDiv);
7498 this._inDialog = false;
7502 /* Tidy up after a dialog display. */
7503 _tidyDialog: function(inst) {
7504 inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar");
7507 /* Close date picker if clicked elsewhere. */
7508 _checkExternalClick: function(event) {
7509 if (!$.datepicker._curInst) {
7513 var $target = $(event.target),
7514 inst = $.datepicker._getInst($target[0]);
7516 if ( ( ( $target[0].id !== $.datepicker._mainDivId &&
7517 $target.parents("#" + $.datepicker._mainDivId).length === 0 &&
7518 !$target.hasClass($.datepicker.markerClassName) &&
7519 !$target.closest("." + $.datepicker._triggerClass).length &&
7520 $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) ||
7521 ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) {
7522 $.datepicker._hideDatepicker();
7526 /* Adjust one of the date sub-fields. */
7527 _adjustDate: function(id, offset, period) {
7529 inst = this._getInst(target[0]);
7531 if (this._isDisabledDatepicker(target[0])) {
7534 this._adjustInstDate(inst, offset +
7535 (period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning
7537 this._updateDatepicker(inst);
7540 /* Action for current link. */
7541 _gotoToday: function(id) {
7544 inst = this._getInst(target[0]);
7546 if (this._get(inst, "gotoCurrent") && inst.currentDay) {
7547 inst.selectedDay = inst.currentDay;
7548 inst.drawMonth = inst.selectedMonth = inst.currentMonth;
7549 inst.drawYear = inst.selectedYear = inst.currentYear;
7552 inst.selectedDay = date.getDate();
7553 inst.drawMonth = inst.selectedMonth = date.getMonth();
7554 inst.drawYear = inst.selectedYear = date.getFullYear();
7556 this._notifyChange(inst);
7557 this._adjustDate(target);
7560 /* Action for selecting a new month/year. */
7561 _selectMonthYear: function(id, select, period) {
7563 inst = this._getInst(target[0]);
7565 inst["selected" + (period === "M" ? "Month" : "Year")] =
7566 inst["draw" + (period === "M" ? "Month" : "Year")] =
7567 parseInt(select.options[select.selectedIndex].value,10);
7569 this._notifyChange(inst);
7570 this._adjustDate(target);
7573 /* Action for selecting a day. */
7574 _selectDay: function(id, month, year, td) {
7578 if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
7582 inst = this._getInst(target[0]);
7583 inst.selectedDay = inst.currentDay = $("a", td).html();
7584 inst.selectedMonth = inst.currentMonth = month;
7585 inst.selectedYear = inst.currentYear = year;
7586 this._selectDate(id, this._formatDate(inst,
7587 inst.currentDay, inst.currentMonth, inst.currentYear));
7590 /* Erase the input field and hide the date picker. */
7591 _clearDate: function(id) {
7593 this._selectDate(target, "");
7596 /* Update the input field with the selected date. */
7597 _selectDate: function(id, dateStr) {
7600 inst = this._getInst(target[0]);
7602 dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
7604 inst.input.val(dateStr);
7606 this._updateAlternate(inst);
7608 onSelect = this._get(inst, "onSelect");
7610 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
7611 } else if (inst.input) {
7612 inst.input.trigger("change"); // fire the change event
7616 this._updateDatepicker(inst);
7618 this._hideDatepicker();
7619 this._lastInput = inst.input[0];
7620 if (typeof(inst.input[0]) !== "object") {
7621 inst.input.focus(); // restore focus
7623 this._lastInput = null;
7627 /* Update any alternate field to synchronise with the main field. */
7628 _updateAlternate: function(inst) {
7629 var altFormat, date, dateStr,
7630 altField = this._get(inst, "altField");
7632 if (altField) { // update alternate field too
7633 altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat");
7634 date = this._getDate(inst);
7635 dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
7636 $(altField).each(function() { $(this).val(dateStr); });
7640 /* Set as beforeShowDay function to prevent selection of weekends.
7641 * @param date Date - the date to customise
7642 * @return [boolean, string] - is this date selectable?, what is its CSS class?
7644 noWeekends: function(date) {
7645 var day = date.getDay();
7646 return [(day > 0 && day < 6), ""];
7649 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
7650 * @param date Date - the date to get the week for
7651 * @return number - the number of the week within the year that contains this date
7653 iso8601Week: function(date) {
7655 checkDate = new Date(date.getTime());
7657 // Find Thursday of this week starting on Monday
7658 checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
7660 time = checkDate.getTime();
7661 checkDate.setMonth(0); // Compare with Jan 1
7662 checkDate.setDate(1);
7663 return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
7666 /* Parse a string value into a date object.
7667 * See formatDate below for the possible formats.
7669 * @param format string - the expected format of the date
7670 * @param value string - the date in the above format
7671 * @param settings Object - attributes include:
7672 * shortYearCutoff number - the cutoff year for determining the century (optional)
7673 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
7674 * dayNames string[7] - names of the days from Sunday (optional)
7675 * monthNamesShort string[12] - abbreviated names of the months (optional)
7676 * monthNames string[12] - names of the months (optional)
7677 * @return Date - the extracted date value or null if value is blank
7679 parseDate: function (format, value, settings) {
7680 if (format == null || value == null) {
7681 throw "Invalid arguments";
7684 value = (typeof value === "object" ? value.toString() : value + "");
7689 var iFormat, dim, extra,
7691 shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff,
7692 shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
7693 new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)),
7694 dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
7695 dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
7696 monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
7697 monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
7704 // Check whether a format character is doubled
7705 lookAhead = function(match) {
7706 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
7712 // Extract a number from the string value
7713 getNumber = function(match) {
7714 var isDoubled = lookAhead(match),
7715 size = (match === "@" ? 14 : (match === "!" ? 20 :
7716 (match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))),
7717 minSize = (match === "y" ? size : 1),
7718 digits = new RegExp("^\\d{" + minSize + "," + size + "}"),
7719 num = value.substring(iValue).match(digits);
7721 throw "Missing number at position " + iValue;
7723 iValue += num[0].length;
7724 return parseInt(num[0], 10);
7726 // Extract a name from the string value and convert to an index
7727 getName = function(match, shortNames, longNames) {
7729 names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {
7731 }).sort(function (a, b) {
7732 return -(a[1].length - b[1].length);
7735 $.each(names, function (i, pair) {
7737 if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) {
7739 iValue += name.length;
7746 throw "Unknown name at position " + iValue;
7749 // Confirm that a literal character matches the string value
7750 checkLiteral = function() {
7751 if (value.charAt(iValue) !== format.charAt(iFormat)) {
7752 throw "Unexpected literal at position " + iValue;
7757 for (iFormat = 0; iFormat < format.length; iFormat++) {
7759 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
7765 switch (format.charAt(iFormat)) {
7767 day = getNumber("d");
7770 getName("D", dayNamesShort, dayNames);
7773 doy = getNumber("o");
7776 month = getNumber("m");
7779 month = getName("M", monthNamesShort, monthNames);
7782 year = getNumber("y");
7785 date = new Date(getNumber("@"));
7786 year = date.getFullYear();
7787 month = date.getMonth() + 1;
7788 day = date.getDate();
7791 date = new Date((getNumber("!") - this._ticksTo1970) / 10000);
7792 year = date.getFullYear();
7793 month = date.getMonth() + 1;
7794 day = date.getDate();
7797 if (lookAhead("'")){
7809 if (iValue < value.length){
7810 extra = value.substr(iValue);
7811 if (!/^\s+/.test(extra)) {
7812 throw "Extra/unparsed characters found in date: " + extra;
7817 year = new Date().getFullYear();
7818 } else if (year < 100) {
7819 year += new Date().getFullYear() - new Date().getFullYear() % 100 +
7820 (year <= shortYearCutoff ? 0 : -100);
7827 dim = this._getDaysInMonth(year, month - 1);
7836 date = this._daylightSavingAdjust(new Date(year, month - 1, day));
7837 if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) {
7838 throw "Invalid date"; // E.g. 31/02/00
7843 /* Standard date formats. */
7844 ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
7845 COOKIE: "D, dd M yy",
7846 ISO_8601: "yy-mm-dd",
7847 RFC_822: "D, d M y",
7848 RFC_850: "DD, dd-M-y",
7849 RFC_1036: "D, d M y",
7850 RFC_1123: "D, d M yy",
7851 RFC_2822: "D, d M yy",
7852 RSS: "D, d M y", // RFC 822
7855 W3C: "yy-mm-dd", // ISO 8601
7857 _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
7858 Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
7860 /* Format a date object into a string value.
7861 * The format can be combinations of the following:
7862 * d - day of month (no leading zero)
7863 * dd - day of month (two digit)
7864 * o - day of year (no leading zeros)
7865 * oo - day of year (three digit)
7866 * D - day name short
7867 * DD - day name long
7868 * m - month of year (no leading zero)
7869 * mm - month of year (two digit)
7870 * M - month name short
7871 * MM - month name long
7872 * y - year (two digit)
7873 * yy - year (four digit)
7874 * @ - Unix timestamp (ms since 01/01/1970)
7875 * ! - Windows ticks (100ns since 01/01/0001)
7876 * "..." - literal text
7879 * @param format string - the desired format of the date
7880 * @param date Date - the date value to format
7881 * @param settings Object - attributes include:
7882 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
7883 * dayNames string[7] - names of the days from Sunday (optional)
7884 * monthNamesShort string[12] - abbreviated names of the months (optional)
7885 * monthNames string[12] - names of the months (optional)
7886 * @return string - the date in the above format
7888 formatDate: function (format, date, settings) {
7894 dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
7895 dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
7896 monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
7897 monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
7898 // Check whether a format character is doubled
7899 lookAhead = function(match) {
7900 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
7906 // Format a number, with leading zero if necessary
7907 formatNumber = function(match, value, len) {
7908 var num = "" + value;
7909 if (lookAhead(match)) {
7910 while (num.length < len) {
7916 // Format a name, short or long as requested
7917 formatName = function(match, value, shortNames, longNames) {
7918 return (lookAhead(match) ? longNames[value] : shortNames[value]);
7924 for (iFormat = 0; iFormat < format.length; iFormat++) {
7926 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
7929 output += format.charAt(iFormat);
7932 switch (format.charAt(iFormat)) {
7934 output += formatNumber("d", date.getDate(), 2);
7937 output += formatName("D", date.getDay(), dayNamesShort, dayNames);
7940 output += formatNumber("o",
7941 Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);
7944 output += formatNumber("m", date.getMonth() + 1, 2);
7947 output += formatName("M", date.getMonth(), monthNamesShort, monthNames);
7950 output += (lookAhead("y") ? date.getFullYear() :
7951 (date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100);
7954 output += date.getTime();
7957 output += date.getTime() * 10000 + this._ticksTo1970;
7960 if (lookAhead("'")) {
7967 output += format.charAt(iFormat);
7975 /* Extract all possible characters from the date format. */
7976 _possibleChars: function (format) {
7980 // Check whether a format character is doubled
7981 lookAhead = function(match) {
7982 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
7989 for (iFormat = 0; iFormat < format.length; iFormat++) {
7991 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
7994 chars += format.charAt(iFormat);
7997 switch (format.charAt(iFormat)) {
7998 case "d": case "m": case "y": case "@":
7999 chars += "0123456789";
8002 return null; // Accept anything
8004 if (lookAhead("'")) {
8011 chars += format.charAt(iFormat);
8018 /* Get a setting value, defaulting if necessary. */
8019 _get: function(inst, name) {
8020 return inst.settings[name] !== undefined ?
8021 inst.settings[name] : this._defaults[name];
8024 /* Parse existing date and initialise date picker. */
8025 _setDateFromField: function(inst, noDefault) {
8026 if (inst.input.val() === inst.lastVal) {
8030 var dateFormat = this._get(inst, "dateFormat"),
8031 dates = inst.lastVal = inst.input ? inst.input.val() : null,
8032 defaultDate = this._getDefaultDate(inst),
8034 settings = this._getFormatConfig(inst);
8037 date = this.parseDate(dateFormat, dates, settings) || defaultDate;
8039 dates = (noDefault ? "" : dates);
8041 inst.selectedDay = date.getDate();
8042 inst.drawMonth = inst.selectedMonth = date.getMonth();
8043 inst.drawYear = inst.selectedYear = date.getFullYear();
8044 inst.currentDay = (dates ? date.getDate() : 0);
8045 inst.currentMonth = (dates ? date.getMonth() : 0);
8046 inst.currentYear = (dates ? date.getFullYear() : 0);
8047 this._adjustInstDate(inst);
8050 /* Retrieve the default date shown on opening. */
8051 _getDefaultDate: function(inst) {
8052 return this._restrictMinMax(inst,
8053 this._determineDate(inst, this._get(inst, "defaultDate"), new Date()));
8056 /* A date may be specified as an exact value or a relative one. */
8057 _determineDate: function(inst, date, defaultDate) {
8058 var offsetNumeric = function(offset) {
8059 var date = new Date();
8060 date.setDate(date.getDate() + offset);
8063 offsetString = function(offset) {
8065 return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
8066 offset, $.datepicker._getFormatConfig(inst));
8072 var date = (offset.toLowerCase().match(/^c/) ?
8073 $.datepicker._getDate(inst) : null) || new Date(),
8074 year = date.getFullYear(),
8075 month = date.getMonth(),
8076 day = date.getDate(),
8077 pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
8078 matches = pattern.exec(offset);
8081 switch (matches[2] || "d") {
8082 case "d" : case "D" :
8083 day += parseInt(matches[1],10); break;
8084 case "w" : case "W" :
8085 day += parseInt(matches[1],10) * 7; break;
8086 case "m" : case "M" :
8087 month += parseInt(matches[1],10);
8088 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
8090 case "y": case "Y" :
8091 year += parseInt(matches[1],10);
8092 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
8095 matches = pattern.exec(offset);
8097 return new Date(year, month, day);
8099 newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) :
8100 (typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));
8102 newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate);
8104 newDate.setHours(0);
8105 newDate.setMinutes(0);
8106 newDate.setSeconds(0);
8107 newDate.setMilliseconds(0);
8109 return this._daylightSavingAdjust(newDate);
8112 /* Handle switch to/from daylight saving.
8113 * Hours may be non-zero on daylight saving cut-over:
8114 * > 12 when midnight changeover, but then cannot generate
8115 * midnight datetime, so jump to 1AM, otherwise reset.
8116 * @param date (Date) the date to check
8117 * @return (Date) the corrected date
8119 _daylightSavingAdjust: function(date) {
8123 date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
8127 /* Set the date(s) directly. */
8128 _setDate: function(inst, date, noChange) {
8130 origMonth = inst.selectedMonth,
8131 origYear = inst.selectedYear,
8132 newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
8134 inst.selectedDay = inst.currentDay = newDate.getDate();
8135 inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
8136 inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
8137 if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) {
8138 this._notifyChange(inst);
8140 this._adjustInstDate(inst);
8142 inst.input.val(clear ? "" : this._formatDate(inst));
8146 /* Retrieve the date(s) directly. */
8147 _getDate: function(inst) {
8148 var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null :
8149 this._daylightSavingAdjust(new Date(
8150 inst.currentYear, inst.currentMonth, inst.currentDay)));
8154 /* Attach the onxxx handlers. These are declared statically so
8155 * they work with static code transformers like Caja.
8157 _attachHandlers: function(inst) {
8158 var stepMonths = this._get(inst, "stepMonths"),
8159 id = "#" + inst.id.replace( /\\\\/g, "\\" );
8160 inst.dpDiv.find("[data-handler]").map(function () {
8163 $.datepicker._adjustDate(id, -stepMonths, "M");
8166 $.datepicker._adjustDate(id, +stepMonths, "M");
8169 $.datepicker._hideDatepicker();
8171 today: function () {
8172 $.datepicker._gotoToday(id);
8174 selectDay: function () {
8175 $.datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this);
8178 selectMonth: function () {
8179 $.datepicker._selectMonthYear(id, this, "M");
8182 selectYear: function () {
8183 $.datepicker._selectMonthYear(id, this, "Y");
8187 $(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]);
8191 /* Generate the HTML for the current state of the date picker. */
8192 _generateHTML: function(inst) {
8193 var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
8194 controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
8195 monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
8196 selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
8197 cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
8198 printDate, dRow, tbody, daySettings, otherMonth, unselectable,
8199 tempDate = new Date(),
8200 today = this._daylightSavingAdjust(
8201 new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time
8202 isRTL = this._get(inst, "isRTL"),
8203 showButtonPanel = this._get(inst, "showButtonPanel"),
8204 hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"),
8205 navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"),
8206 numMonths = this._getNumberOfMonths(inst),
8207 showCurrentAtPos = this._get(inst, "showCurrentAtPos"),
8208 stepMonths = this._get(inst, "stepMonths"),
8209 isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1),
8210 currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
8211 new Date(inst.currentYear, inst.currentMonth, inst.currentDay))),
8212 minDate = this._getMinMaxDate(inst, "min"),
8213 maxDate = this._getMinMaxDate(inst, "max"),
8214 drawMonth = inst.drawMonth - showCurrentAtPos,
8215 drawYear = inst.drawYear;
8217 if (drawMonth < 0) {
8222 maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
8223 maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
8224 maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
8225 while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
8227 if (drawMonth < 0) {
8233 inst.drawMonth = drawMonth;
8234 inst.drawYear = drawYear;
8236 prevText = this._get(inst, "prevText");
8237 prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
8238 this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
8239 this._getFormatConfig(inst)));
8241 prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
8242 "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
8243 " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" :
8244 (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>"));
8246 nextText = this._get(inst, "nextText");
8247 nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
8248 this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
8249 this._getFormatConfig(inst)));
8251 next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
8252 "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
8253 " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" :
8254 (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>"));
8256 currentText = this._get(inst, "currentText");
8257 gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today);
8258 currentText = (!navigationAsDateFormat ? currentText :
8259 this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
8261 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'>" +
8262 this._get(inst, "closeText") + "</button>" : "");
8264 buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") +
8265 (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'" +
8266 ">" + currentText + "</button>" : "") + (isRTL ? "" : controls) + "</div>" : "";
8268 firstDay = parseInt(this._get(inst, "firstDay"),10);
8269 firstDay = (isNaN(firstDay) ? 0 : firstDay);
8271 showWeek = this._get(inst, "showWeek");
8272 dayNames = this._get(inst, "dayNames");
8273 dayNamesMin = this._get(inst, "dayNamesMin");
8274 monthNames = this._get(inst, "monthNames");
8275 monthNamesShort = this._get(inst, "monthNamesShort");
8276 beforeShowDay = this._get(inst, "beforeShowDay");
8277 showOtherMonths = this._get(inst, "showOtherMonths");
8278 selectOtherMonths = this._get(inst, "selectOtherMonths");
8279 defaultDate = this._getDefaultDate(inst);
8282 for (row = 0; row < numMonths[0]; row++) {
8285 for (col = 0; col < numMonths[1]; col++) {
8286 selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
8287 cornerClass = " ui-corner-all";
8290 calender += "<div class='ui-datepicker-group";
8291 if (numMonths[1] > 1) {
8293 case 0: calender += " ui-datepicker-group-first";
8294 cornerClass = " ui-corner-" + (isRTL ? "right" : "left"); break;
8295 case numMonths[1]-1: calender += " ui-datepicker-group-last";
8296 cornerClass = " ui-corner-" + (isRTL ? "left" : "right"); break;
8297 default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
8302 calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
8303 (/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") +
8304 (/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") +
8305 this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
8306 row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
8307 "</div><table class='ui-datepicker-calendar'><thead>" +
8309 thead = (showWeek ? "<th class='ui-datepicker-week-col'>" + this._get(inst, "weekHeader") + "</th>" : "");
8310 for (dow = 0; dow < 7; dow++) { // days of the week
8311 day = (dow + firstDay) % 7;
8312 thead += "<th scope='col'" + ((dow + firstDay + 6) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "") + ">" +
8313 "<span title='" + dayNames[day] + "'>" + dayNamesMin[day] + "</span></th>";
8315 calender += thead + "</tr></thead><tbody>";
8316 daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
8317 if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) {
8318 inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
8320 leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
8321 curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate
8322 numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043)
8323 this.maxRows = numRows;
8324 printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
8325 for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows
8327 tbody = (!showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
8328 this._get(inst, "calculateWeek")(printDate) + "</td>");
8329 for (dow = 0; dow < 7; dow++) { // create date picker days
8330 daySettings = (beforeShowDay ?
8331 beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]);
8332 otherMonth = (printDate.getMonth() !== drawMonth);
8333 unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
8334 (minDate && printDate < minDate) || (maxDate && printDate > maxDate);
8335 tbody += "<td class='" +
8336 ((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends
8337 (otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months
8338 ((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key
8339 (defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ?
8340 // or defaultDate is current printedDate and defaultDate is selectedDate
8341 " " + this._dayOverClass : "") + // highlight selected day
8342 (unselectable ? " " + this._unselectableClass + " ui-state-disabled": "") + // highlight unselectable days
8343 (otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates
8344 (printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day
8345 (printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different)
8346 ((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "'") + "'" : "") + // cell title
8347 (unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions
8348 (otherMonth && !showOtherMonths ? " " : // display for other months
8349 (unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
8350 (printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") +
8351 (printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day
8352 (otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months
8353 "' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date
8354 printDate.setDate(printDate.getDate() + 1);
8355 printDate = this._daylightSavingAdjust(printDate);
8357 calender += tbody + "</tr>";
8360 if (drawMonth > 11) {
8364 calender += "</tbody></table>" + (isMultiMonth ? "</div>" +
8365 ((numMonths[0] > 0 && col === numMonths[1]-1) ? "<div class='ui-datepicker-row-break'></div>" : "") : "");
8370 html += buttonPanel;
8371 inst._keyEvent = false;
8375 /* Generate the month and year header. */
8376 _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
8377 secondary, monthNames, monthNamesShort) {
8379 var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
8380 changeMonth = this._get(inst, "changeMonth"),
8381 changeYear = this._get(inst, "changeYear"),
8382 showMonthAfterYear = this._get(inst, "showMonthAfterYear"),
8383 html = "<div class='ui-datepicker-title'>",
8387 if (secondary || !changeMonth) {
8388 monthHtml += "<span class='ui-datepicker-month'>" + monthNames[drawMonth] + "</span>";
8390 inMinYear = (minDate && minDate.getFullYear() === drawYear);
8391 inMaxYear = (maxDate && maxDate.getFullYear() === drawYear);
8392 monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
8393 for ( month = 0; month < 12; month++) {
8394 if ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) {
8395 monthHtml += "<option value='" + month + "'" +
8396 (month === drawMonth ? " selected='selected'" : "") +
8397 ">" + monthNamesShort[month] + "</option>";
8400 monthHtml += "</select>";
8403 if (!showMonthAfterYear) {
8404 html += monthHtml + (secondary || !(changeMonth && changeYear) ? " " : "");
8408 if ( !inst.yearshtml ) {
8409 inst.yearshtml = "";
8410 if (secondary || !changeYear) {
8411 html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
8413 // determine range of years to display
8414 years = this._get(inst, "yearRange").split(":");
8415 thisYear = new Date().getFullYear();
8416 determineYear = function(value) {
8417 var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) :
8418 (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) :
8419 parseInt(value, 10)));
8420 return (isNaN(year) ? thisYear : year);
8422 year = determineYear(years[0]);
8423 endYear = Math.max(year, determineYear(years[1] || ""));
8424 year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
8425 endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
8426 inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
8427 for (; year <= endYear; year++) {
8428 inst.yearshtml += "<option value='" + year + "'" +
8429 (year === drawYear ? " selected='selected'" : "") +
8430 ">" + year + "</option>";
8432 inst.yearshtml += "</select>";
8434 html += inst.yearshtml;
8435 inst.yearshtml = null;
8439 html += this._get(inst, "yearSuffix");
8440 if (showMonthAfterYear) {
8441 html += (secondary || !(changeMonth && changeYear) ? " " : "") + monthHtml;
8443 html += "</div>"; // Close datepicker_header
8447 /* Adjust one of the date sub-fields. */
8448 _adjustInstDate: function(inst, offset, period) {
8449 var year = inst.drawYear + (period === "Y" ? offset : 0),
8450 month = inst.drawMonth + (period === "M" ? offset : 0),
8451 day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0),
8452 date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day)));
8454 inst.selectedDay = date.getDate();
8455 inst.drawMonth = inst.selectedMonth = date.getMonth();
8456 inst.drawYear = inst.selectedYear = date.getFullYear();
8457 if (period === "M" || period === "Y") {
8458 this._notifyChange(inst);
8462 /* Ensure a date is within any min/max bounds. */
8463 _restrictMinMax: function(inst, date) {
8464 var minDate = this._getMinMaxDate(inst, "min"),
8465 maxDate = this._getMinMaxDate(inst, "max"),
8466 newDate = (minDate && date < minDate ? minDate : date);
8467 return (maxDate && newDate > maxDate ? maxDate : newDate);
8470 /* Notify change of month/year. */
8471 _notifyChange: function(inst) {
8472 var onChange = this._get(inst, "onChangeMonthYear");
8474 onChange.apply((inst.input ? inst.input[0] : null),
8475 [inst.selectedYear, inst.selectedMonth + 1, inst]);
8479 /* Determine the number of months to show. */
8480 _getNumberOfMonths: function(inst) {
8481 var numMonths = this._get(inst, "numberOfMonths");
8482 return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths));
8485 /* Determine the current maximum date - ensure no time components are set. */
8486 _getMinMaxDate: function(inst, minMax) {
8487 return this._determineDate(inst, this._get(inst, minMax + "Date"), null);
8490 /* Find the number of days in a given month. */
8491 _getDaysInMonth: function(year, month) {
8492 return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();
8495 /* Find the day of the week of the first of a month. */
8496 _getFirstDayOfMonth: function(year, month) {
8497 return new Date(year, month, 1).getDay();
8500 /* Determines if we should allow a "next/prev" month display change. */
8501 _canAdjustMonth: function(inst, offset, curYear, curMonth) {
8502 var numMonths = this._getNumberOfMonths(inst),
8503 date = this._daylightSavingAdjust(new Date(curYear,
8504 curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
8507 date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
8509 return this._isInRange(inst, date);
8512 /* Is the given date in the accepted range? */
8513 _isInRange: function(inst, date) {
8514 var yearSplit, currentYear,
8515 minDate = this._getMinMaxDate(inst, "min"),
8516 maxDate = this._getMinMaxDate(inst, "max"),
8519 years = this._get(inst, "yearRange");
8521 yearSplit = years.split(":");
8522 currentYear = new Date().getFullYear();
8523 minYear = parseInt(yearSplit[0], 10);
8524 maxYear = parseInt(yearSplit[1], 10);
8525 if ( yearSplit[0].match(/[+\-].*/) ) {
8526 minYear += currentYear;
8528 if ( yearSplit[1].match(/[+\-].*/) ) {
8529 maxYear += currentYear;
8533 return ((!minDate || date.getTime() >= minDate.getTime()) &&
8534 (!maxDate || date.getTime() <= maxDate.getTime()) &&
8535 (!minYear || date.getFullYear() >= minYear) &&
8536 (!maxYear || date.getFullYear() <= maxYear));
8539 /* Provide the configuration settings for formatting/parsing. */
8540 _getFormatConfig: function(inst) {
8541 var shortYearCutoff = this._get(inst, "shortYearCutoff");
8542 shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff :
8543 new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
8544 return {shortYearCutoff: shortYearCutoff,
8545 dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"),
8546 monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")};
8549 /* Format the given date for display. */
8550 _formatDate: function(inst, day, month, year) {
8552 inst.currentDay = inst.selectedDay;
8553 inst.currentMonth = inst.selectedMonth;
8554 inst.currentYear = inst.selectedYear;
8556 var date = (day ? (typeof day === "object" ? day :
8557 this._daylightSavingAdjust(new Date(year, month, day))) :
8558 this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
8559 return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst));
8564 * Bind hover events for datepicker elements.
8565 * Done via delegate so the binding only occurs once in the lifetime of the parent div.
8566 * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
8568 function datepicker_bindHover(dpDiv) {
8569 var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
8570 return dpDiv.delegate(selector, "mouseout", function() {
8571 $(this).removeClass("ui-state-hover");
8572 if (this.className.indexOf("ui-datepicker-prev") !== -1) {
8573 $(this).removeClass("ui-datepicker-prev-hover");
8575 if (this.className.indexOf("ui-datepicker-next") !== -1) {
8576 $(this).removeClass("ui-datepicker-next-hover");
8579 .delegate( selector, "mouseover", datepicker_handleMouseover );
8582 function datepicker_handleMouseover() {
8583 if (!$.datepicker._isDisabledDatepicker( datepicker_instActive.inline? datepicker_instActive.dpDiv.parent()[0] : datepicker_instActive.input[0])) {
8584 $(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");
8585 $(this).addClass("ui-state-hover");
8586 if (this.className.indexOf("ui-datepicker-prev") !== -1) {
8587 $(this).addClass("ui-datepicker-prev-hover");
8589 if (this.className.indexOf("ui-datepicker-next") !== -1) {
8590 $(this).addClass("ui-datepicker-next-hover");
8595 /* jQuery extend now ignores nulls! */
8596 function datepicker_extendRemove(target, props) {
8597 $.extend(target, props);
8598 for (var name in props) {
8599 if (props[name] == null) {
8600 target[name] = props[name];
8606 /* Invoke the datepicker functionality.
8607 @param options string - a command, optionally followed by additional parameters or
8608 Object - settings for attaching new datepicker functionality
8609 @return jQuery object */
8610 $.fn.datepicker = function(options){
8612 /* Verify an empty collection wasn't passed - Fixes #6976 */
8613 if ( !this.length ) {
8617 /* Initialise the date picker. */
8618 if (!$.datepicker.initialized) {
8619 $(document).mousedown($.datepicker._checkExternalClick);
8620 $.datepicker.initialized = true;
8623 /* Append datepicker main container to body if not exist. */
8624 if ($("#"+$.datepicker._mainDivId).length === 0) {
8625 $("body").append($.datepicker.dpDiv);
8628 var otherArgs = Array.prototype.slice.call(arguments, 1);
8629 if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) {
8630 return $.datepicker["_" + options + "Datepicker"].
8631 apply($.datepicker, [this[0]].concat(otherArgs));
8633 if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") {
8634 return $.datepicker["_" + options + "Datepicker"].
8635 apply($.datepicker, [this[0]].concat(otherArgs));
8637 return this.each(function() {
8638 typeof options === "string" ?
8639 $.datepicker["_" + options + "Datepicker"].
8640 apply($.datepicker, [this].concat(otherArgs)) :
8641 $.datepicker._attachDatepicker(this, options);
8645 $.datepicker = new Datepicker(); // singleton instance
8646 $.datepicker.initialized = false;
8647 $.datepicker.uuid = new Date().getTime();
8648 $.datepicker.version = "1.11.4";
8650 var datepicker = $.datepicker;
8654 * jQuery UI Progressbar 1.11.4
8655 * http://jqueryui.com
8657 * Copyright jQuery Foundation and other contributors
8658 * Released under the MIT license.
8659 * http://jquery.org/license
8661 * http://api.jqueryui.com/progressbar/
8665 var progressbar = $.widget( "ui.progressbar", {
8677 _create: function() {
8678 // Constrain initial value
8679 this.oldValue = this.options.value = this._constrainedValue();
8682 .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
8684 // Only set static values, aria-valuenow and aria-valuemax are
8685 // set inside _refreshValue()
8686 role: "progressbar",
8687 "aria-valuemin": this.min
8690 this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" )
8691 .appendTo( this.element );
8693 this._refreshValue();
8696 _destroy: function() {
8698 .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
8699 .removeAttr( "role" )
8700 .removeAttr( "aria-valuemin" )
8701 .removeAttr( "aria-valuemax" )
8702 .removeAttr( "aria-valuenow" );
8704 this.valueDiv.remove();
8707 value: function( newValue ) {
8708 if ( newValue === undefined ) {
8709 return this.options.value;
8712 this.options.value = this._constrainedValue( newValue );
8713 this._refreshValue();
8716 _constrainedValue: function( newValue ) {
8717 if ( newValue === undefined ) {
8718 newValue = this.options.value;
8721 this.indeterminate = newValue === false;
8724 if ( typeof newValue !== "number" ) {
8728 return this.indeterminate ? false :
8729 Math.min( this.options.max, Math.max( this.min, newValue ) );
8732 _setOptions: function( options ) {
8733 // Ensure "value" option is set after other values (like max)
8734 var value = options.value;
8735 delete options.value;
8737 this._super( options );
8739 this.options.value = this._constrainedValue( value );
8740 this._refreshValue();
8743 _setOption: function( key, value ) {
8744 if ( key === "max" ) {
8745 // Don't allow a max less than min
8746 value = Math.max( this.min, value );
8748 if ( key === "disabled" ) {
8750 .toggleClass( "ui-state-disabled", !!value )
8751 .attr( "aria-disabled", value );
8753 this._super( key, value );
8756 _percentage: function() {
8757 return this.indeterminate ? 100 : 100 * ( this.options.value - this.min ) / ( this.options.max - this.min );
8760 _refreshValue: function() {
8761 var value = this.options.value,
8762 percentage = this._percentage();
8765 .toggle( this.indeterminate || value > this.min )
8766 .toggleClass( "ui-corner-right", value === this.options.max )
8767 .width( percentage.toFixed(0) + "%" );
8769 this.element.toggleClass( "ui-progressbar-indeterminate", this.indeterminate );
8771 if ( this.indeterminate ) {
8772 this.element.removeAttr( "aria-valuenow" );
8773 if ( !this.overlayDiv ) {
8774 this.overlayDiv = $( "<div class='ui-progressbar-overlay'></div>" ).appendTo( this.valueDiv );
8778 "aria-valuemax": this.options.max,
8779 "aria-valuenow": value
8781 if ( this.overlayDiv ) {
8782 this.overlayDiv.remove();
8783 this.overlayDiv = null;
8787 if ( this.oldValue !== value ) {
8788 this.oldValue = value;
8789 this._trigger( "change" );
8791 if ( value === this.options.max ) {
8792 this._trigger( "complete" );
8799 * jQuery UI Slider 1.11.4
8800 * http://jqueryui.com
8802 * Copyright jQuery Foundation and other contributors
8803 * Released under the MIT license.
8804 * http://jquery.org/license
8806 * http://api.jqueryui.com/slider/
8810 var slider = $.widget( "ui.slider", $.ui.mouse, {
8812 widgetEventPrefix: "slide",
8819 orientation: "horizontal",
8832 // number of pages in a slider
8833 // (how many times can you page up/down to go through the whole range)
8836 _create: function() {
8837 this._keySliding = false;
8838 this._mouseSliding = false;
8839 this._animateOff = true;
8840 this._handleIndex = null;
8841 this._detectOrientation();
8843 this._calculateNewMax();
8846 .addClass( "ui-slider" +
8847 " ui-slider-" + this.orientation +
8849 " ui-widget-content" +
8853 this._setOption( "disabled", this.options.disabled );
8855 this._animateOff = false;
8858 _refresh: function() {
8859 this._createRange();
8860 this._createHandles();
8861 this._setupEvents();
8862 this._refreshValue();
8865 _createHandles: function() {
8867 options = this.options,
8868 existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ),
8869 handle = "<span class='ui-slider-handle ui-state-default ui-corner-all' tabindex='0'></span>",
8872 handleCount = ( options.values && options.values.length ) || 1;
8874 if ( existingHandles.length > handleCount ) {
8875 existingHandles.slice( handleCount ).remove();
8876 existingHandles = existingHandles.slice( 0, handleCount );
8879 for ( i = existingHandles.length; i < handleCount; i++ ) {
8880 handles.push( handle );
8883 this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
8885 this.handle = this.handles.eq( 0 );
8887 this.handles.each(function( i ) {
8888 $( this ).data( "ui-slider-handle-index", i );
8892 _createRange: function() {
8893 var options = this.options,
8896 if ( options.range ) {
8897 if ( options.range === true ) {
8898 if ( !options.values ) {
8899 options.values = [ this._valueMin(), this._valueMin() ];
8900 } else if ( options.values.length && options.values.length !== 2 ) {
8901 options.values = [ options.values[0], options.values[0] ];
8902 } else if ( $.isArray( options.values ) ) {
8903 options.values = options.values.slice(0);
8907 if ( !this.range || !this.range.length ) {
8908 this.range = $( "<div></div>" )
8909 .appendTo( this.element );
8911 classes = "ui-slider-range" +
8912 // note: this isn't the most fittingly semantic framework class for this element,
8913 // but worked best visually with a variety of themes
8914 " ui-widget-header ui-corner-all";
8916 this.range.removeClass( "ui-slider-range-min ui-slider-range-max" )
8917 // Handle range switching from true to min/max
8924 this.range.addClass( classes +
8925 ( ( options.range === "min" || options.range === "max" ) ? " ui-slider-range-" + options.range : "" ) );
8928 this.range.remove();
8934 _setupEvents: function() {
8935 this._off( this.handles );
8936 this._on( this.handles, this._handleEvents );
8937 this._hoverable( this.handles );
8938 this._focusable( this.handles );
8941 _destroy: function() {
8942 this.handles.remove();
8944 this.range.remove();
8948 .removeClass( "ui-slider" +
8949 " ui-slider-horizontal" +
8950 " ui-slider-vertical" +
8952 " ui-widget-content" +
8955 this._mouseDestroy();
8958 _mouseCapture: function( event ) {
8959 var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
8967 this.elementSize = {
8968 width: this.element.outerWidth(),
8969 height: this.element.outerHeight()
8971 this.elementOffset = this.element.offset();
8973 position = { x: event.pageX, y: event.pageY };
8974 normValue = this._normValueFromMouse( position );
8975 distance = this._valueMax() - this._valueMin() + 1;
8976 this.handles.each(function( i ) {
8977 var thisDistance = Math.abs( normValue - that.values(i) );
8978 if (( distance > thisDistance ) ||
8979 ( distance === thisDistance &&
8980 (i === that._lastChangedValue || that.values(i) === o.min ))) {
8981 distance = thisDistance;
8982 closestHandle = $( this );
8987 allowed = this._start( event, index );
8988 if ( allowed === false ) {
8991 this._mouseSliding = true;
8993 this._handleIndex = index;
8996 .addClass( "ui-state-active" )
8999 offset = closestHandle.offset();
9000 mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
9001 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
9002 left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
9003 top: event.pageY - offset.top -
9004 ( closestHandle.height() / 2 ) -
9005 ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) -
9006 ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) +
9007 ( parseInt( closestHandle.css("marginTop"), 10 ) || 0)
9010 if ( !this.handles.hasClass( "ui-state-hover" ) ) {
9011 this._slide( event, index, normValue );
9013 this._animateOff = true;
9017 _mouseStart: function() {
9021 _mouseDrag: function( event ) {
9022 var position = { x: event.pageX, y: event.pageY },
9023 normValue = this._normValueFromMouse( position );
9025 this._slide( event, this._handleIndex, normValue );
9030 _mouseStop: function( event ) {
9031 this.handles.removeClass( "ui-state-active" );
9032 this._mouseSliding = false;
9034 this._stop( event, this._handleIndex );
9035 this._change( event, this._handleIndex );
9037 this._handleIndex = null;
9038 this._clickOffset = null;
9039 this._animateOff = false;
9044 _detectOrientation: function() {
9045 this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
9048 _normValueFromMouse: function( position ) {
9055 if ( this.orientation === "horizontal" ) {
9056 pixelTotal = this.elementSize.width;
9057 pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
9059 pixelTotal = this.elementSize.height;
9060 pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );
9063 percentMouse = ( pixelMouse / pixelTotal );
9064 if ( percentMouse > 1 ) {
9067 if ( percentMouse < 0 ) {
9070 if ( this.orientation === "vertical" ) {
9071 percentMouse = 1 - percentMouse;
9074 valueTotal = this._valueMax() - this._valueMin();
9075 valueMouse = this._valueMin() + percentMouse * valueTotal;
9077 return this._trimAlignValue( valueMouse );
9080 _start: function( event, index ) {
9082 handle: this.handles[ index ],
9085 if ( this.options.values && this.options.values.length ) {
9086 uiHash.value = this.values( index );
9087 uiHash.values = this.values();
9089 return this._trigger( "start", event, uiHash );
9092 _slide: function( event, index, newVal ) {
9097 if ( this.options.values && this.options.values.length ) {
9098 otherVal = this.values( index ? 0 : 1 );
9100 if ( ( this.options.values.length === 2 && this.options.range === true ) &&
9101 ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )
9106 if ( newVal !== this.values( index ) ) {
9107 newValues = this.values();
9108 newValues[ index ] = newVal;
9109 // A slide can be canceled by returning false from the slide callback
9110 allowed = this._trigger( "slide", event, {
9111 handle: this.handles[ index ],
9115 otherVal = this.values( index ? 0 : 1 );
9116 if ( allowed !== false ) {
9117 this.values( index, newVal );
9121 if ( newVal !== this.value() ) {
9122 // A slide can be canceled by returning false from the slide callback
9123 allowed = this._trigger( "slide", event, {
9124 handle: this.handles[ index ],
9127 if ( allowed !== false ) {
9128 this.value( newVal );
9134 _stop: function( event, index ) {
9136 handle: this.handles[ index ],
9139 if ( this.options.values && this.options.values.length ) {
9140 uiHash.value = this.values( index );
9141 uiHash.values = this.values();
9144 this._trigger( "stop", event, uiHash );
9147 _change: function( event, index ) {
9148 if ( !this._keySliding && !this._mouseSliding ) {
9150 handle: this.handles[ index ],
9153 if ( this.options.values && this.options.values.length ) {
9154 uiHash.value = this.values( index );
9155 uiHash.values = this.values();
9158 //store the last changed value index for reference when handles overlap
9159 this._lastChangedValue = index;
9161 this._trigger( "change", event, uiHash );
9165 value: function( newValue ) {
9166 if ( arguments.length ) {
9167 this.options.value = this._trimAlignValue( newValue );
9168 this._refreshValue();
9169 this._change( null, 0 );
9173 return this._value();
9176 values: function( index, newValue ) {
9181 if ( arguments.length > 1 ) {
9182 this.options.values[ index ] = this._trimAlignValue( newValue );
9183 this._refreshValue();
9184 this._change( null, index );
9188 if ( arguments.length ) {
9189 if ( $.isArray( arguments[ 0 ] ) ) {
9190 vals = this.options.values;
9191 newValues = arguments[ 0 ];
9192 for ( i = 0; i < vals.length; i += 1 ) {
9193 vals[ i ] = this._trimAlignValue( newValues[ i ] );
9194 this._change( null, i );
9196 this._refreshValue();
9198 if ( this.options.values && this.options.values.length ) {
9199 return this._values( index );
9201 return this.value();
9205 return this._values();
9209 _setOption: function( key, value ) {
9213 if ( key === "range" && this.options.range === true ) {
9214 if ( value === "min" ) {
9215 this.options.value = this._values( 0 );
9216 this.options.values = null;
9217 } else if ( value === "max" ) {
9218 this.options.value = this._values( this.options.values.length - 1 );
9219 this.options.values = null;
9223 if ( $.isArray( this.options.values ) ) {
9224 valsLength = this.options.values.length;
9227 if ( key === "disabled" ) {
9228 this.element.toggleClass( "ui-state-disabled", !!value );
9231 this._super( key, value );
9235 this._detectOrientation();
9237 .removeClass( "ui-slider-horizontal ui-slider-vertical" )
9238 .addClass( "ui-slider-" + this.orientation );
9239 this._refreshValue();
9241 // Reset positioning from previous orientation
9242 this.handles.css( value === "horizontal" ? "bottom" : "left", "" );
9245 this._animateOff = true;
9246 this._refreshValue();
9247 this._change( null, 0 );
9248 this._animateOff = false;
9251 this._animateOff = true;
9252 this._refreshValue();
9253 for ( i = 0; i < valsLength; i += 1 ) {
9254 this._change( null, i );
9256 this._animateOff = false;
9261 this._animateOff = true;
9262 this._calculateNewMax();
9263 this._refreshValue();
9264 this._animateOff = false;
9267 this._animateOff = true;
9269 this._animateOff = false;
9274 //internal value getter
9275 // _value() returns value trimmed by min and max, aligned by step
9276 _value: function() {
9277 var val = this.options.value;
9278 val = this._trimAlignValue( val );
9283 //internal values getter
9284 // _values() returns array of values trimmed by min and max, aligned by step
9285 // _values( index ) returns single value trimmed by min and max, aligned by step
9286 _values: function( index ) {
9291 if ( arguments.length ) {
9292 val = this.options.values[ index ];
9293 val = this._trimAlignValue( val );
9296 } else if ( this.options.values && this.options.values.length ) {
9297 // .slice() creates a copy of the array
9298 // this copy gets trimmed by min and max and then returned
9299 vals = this.options.values.slice();
9300 for ( i = 0; i < vals.length; i += 1) {
9301 vals[ i ] = this._trimAlignValue( vals[ i ] );
9310 // returns the step-aligned value that val is closest to, between (inclusive) min and max
9311 _trimAlignValue: function( val ) {
9312 if ( val <= this._valueMin() ) {
9313 return this._valueMin();
9315 if ( val >= this._valueMax() ) {
9316 return this._valueMax();
9318 var step = ( this.options.step > 0 ) ? this.options.step : 1,
9319 valModStep = (val - this._valueMin()) % step,
9320 alignValue = val - valModStep;
9322 if ( Math.abs(valModStep) * 2 >= step ) {
9323 alignValue += ( valModStep > 0 ) ? step : ( -step );
9326 // Since JavaScript has problems with large floats, round
9327 // the final value to 5 digits after the decimal point (see #4124)
9328 return parseFloat( alignValue.toFixed(5) );
9331 _calculateNewMax: function() {
9332 var max = this.options.max,
9333 min = this._valueMin(),
9334 step = this.options.step,
9335 aboveMin = Math.floor( ( +( max - min ).toFixed( this._precision() ) ) / step ) * step;
9336 max = aboveMin + min;
9337 this.max = parseFloat( max.toFixed( this._precision() ) );
9340 _precision: function() {
9341 var precision = this._precisionOf( this.options.step );
9342 if ( this.options.min !== null ) {
9343 precision = Math.max( precision, this._precisionOf( this.options.min ) );
9348 _precisionOf: function( num ) {
9349 var str = num.toString(),
9350 decimal = str.indexOf( "." );
9351 return decimal === -1 ? 0 : str.length - decimal - 1;
9354 _valueMin: function() {
9355 return this.options.min;
9358 _valueMax: function() {
9362 _refreshValue: function() {
9363 var lastValPercent, valPercent, value, valueMin, valueMax,
9364 oRange = this.options.range,
9367 animate = ( !this._animateOff ) ? o.animate : false,
9370 if ( this.options.values && this.options.values.length ) {
9371 this.handles.each(function( i ) {
9372 valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100;
9373 _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
9374 $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
9375 if ( that.options.range === true ) {
9376 if ( that.orientation === "horizontal" ) {
9378 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate );
9381 that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
9385 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate );
9388 that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
9392 lastValPercent = valPercent;
9395 value = this.value();
9396 valueMin = this._valueMin();
9397 valueMax = this._valueMax();
9398 valPercent = ( valueMax !== valueMin ) ?
9399 ( value - valueMin ) / ( valueMax - valueMin ) * 100 :
9401 _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
9402 this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
9404 if ( oRange === "min" && this.orientation === "horizontal" ) {
9405 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate );
9407 if ( oRange === "max" && this.orientation === "horizontal" ) {
9408 this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
9410 if ( oRange === "min" && this.orientation === "vertical" ) {
9411 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate );
9413 if ( oRange === "max" && this.orientation === "vertical" ) {
9414 this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
9420 keydown: function( event ) {
9421 var allowed, curVal, newVal, step,
9422 index = $( event.target ).data( "ui-slider-handle-index" );
9424 switch ( event.keyCode ) {
9425 case $.ui.keyCode.HOME:
9426 case $.ui.keyCode.END:
9427 case $.ui.keyCode.PAGE_UP:
9428 case $.ui.keyCode.PAGE_DOWN:
9429 case $.ui.keyCode.UP:
9430 case $.ui.keyCode.RIGHT:
9431 case $.ui.keyCode.DOWN:
9432 case $.ui.keyCode.LEFT:
9433 event.preventDefault();
9434 if ( !this._keySliding ) {
9435 this._keySliding = true;
9436 $( event.target ).addClass( "ui-state-active" );
9437 allowed = this._start( event, index );
9438 if ( allowed === false ) {
9445 step = this.options.step;
9446 if ( this.options.values && this.options.values.length ) {
9447 curVal = newVal = this.values( index );
9449 curVal = newVal = this.value();
9452 switch ( event.keyCode ) {
9453 case $.ui.keyCode.HOME:
9454 newVal = this._valueMin();
9456 case $.ui.keyCode.END:
9457 newVal = this._valueMax();
9459 case $.ui.keyCode.PAGE_UP:
9460 newVal = this._trimAlignValue(
9461 curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages )
9464 case $.ui.keyCode.PAGE_DOWN:
9465 newVal = this._trimAlignValue(
9466 curVal - ( (this._valueMax() - this._valueMin()) / this.numPages ) );
9468 case $.ui.keyCode.UP:
9469 case $.ui.keyCode.RIGHT:
9470 if ( curVal === this._valueMax() ) {
9473 newVal = this._trimAlignValue( curVal + step );
9475 case $.ui.keyCode.DOWN:
9476 case $.ui.keyCode.LEFT:
9477 if ( curVal === this._valueMin() ) {
9480 newVal = this._trimAlignValue( curVal - step );
9484 this._slide( event, index, newVal );
9486 keyup: function( event ) {
9487 var index = $( event.target ).data( "ui-slider-handle-index" );
9489 if ( this._keySliding ) {
9490 this._keySliding = false;
9491 this._stop( event, index );
9492 this._change( event, index );
9493 $( event.target ).removeClass( "ui-state-active" );
9501 * jQuery UI Tabs 1.11.4
9502 * http://jqueryui.com
9504 * Copyright jQuery Foundation and other contributors
9505 * Released under the MIT license.
9506 * http://jquery.org/license
9508 * http://api.jqueryui.com/tabs/
9512 var tabs = $.widget( "ui.tabs", {
9519 heightStyle: "content",
9525 beforeActivate: null,
9530 _isLocal: (function() {
9533 return function( anchor ) {
9534 var anchorUrl, locationUrl;
9537 // IE7 doesn't normalize the href property when set via script (#9317)
9538 anchor = anchor.cloneNode( false );
9540 anchorUrl = anchor.href.replace( rhash, "" );
9541 locationUrl = location.href.replace( rhash, "" );
9543 // decoding may throw an error if the URL isn't UTF-8 (#9518)
9545 anchorUrl = decodeURIComponent( anchorUrl );
9546 } catch ( error ) {}
9548 locationUrl = decodeURIComponent( locationUrl );
9549 } catch ( error ) {}
9551 return anchor.hash.length > 1 && anchorUrl === locationUrl;
9555 _create: function() {
9557 options = this.options;
9559 this.running = false;
9562 .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" )
9563 .toggleClass( "ui-tabs-collapsible", options.collapsible );
9565 this._processTabs();
9566 options.active = this._initialActive();
9568 // Take disabling tabs via class attribute from HTML
9569 // into account and update option properly.
9570 if ( $.isArray( options.disabled ) ) {
9571 options.disabled = $.unique( options.disabled.concat(
9572 $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
9573 return that.tabs.index( li );
9578 // check for length avoids error when initializing empty list
9579 if ( this.options.active !== false && this.anchors.length ) {
9580 this.active = this._findActive( options.active );
9587 if ( this.active.length ) {
9588 this.load( options.active );
9592 _initialActive: function() {
9593 var active = this.options.active,
9594 collapsible = this.options.collapsible,
9595 locationHash = location.hash.substring( 1 );
9597 if ( active === null ) {
9598 // check the fragment identifier in the URL
9599 if ( locationHash ) {
9600 this.tabs.each(function( i, tab ) {
9601 if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
9608 // check for a tab marked active via a class
9609 if ( active === null ) {
9610 active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
9613 // no active tab, set to false
9614 if ( active === null || active === -1 ) {
9615 active = this.tabs.length ? 0 : false;
9619 // handle numbers: negative, out of range
9620 if ( active !== false ) {
9621 active = this.tabs.index( this.tabs.eq( active ) );
9622 if ( active === -1 ) {
9623 active = collapsible ? false : 0;
9627 // don't allow collapsible: false and active: false
9628 if ( !collapsible && active === false && this.anchors.length ) {
9635 _getCreateEventData: function() {
9638 panel: !this.active.length ? $() : this._getPanelForTab( this.active )
9642 _tabKeydown: function( event ) {
9643 var focusedTab = $( this.document[0].activeElement ).closest( "li" ),
9644 selectedIndex = this.tabs.index( focusedTab ),
9645 goingForward = true;
9647 if ( this._handlePageNav( event ) ) {
9651 switch ( event.keyCode ) {
9652 case $.ui.keyCode.RIGHT:
9653 case $.ui.keyCode.DOWN:
9656 case $.ui.keyCode.UP:
9657 case $.ui.keyCode.LEFT:
9658 goingForward = false;
9661 case $.ui.keyCode.END:
9662 selectedIndex = this.anchors.length - 1;
9664 case $.ui.keyCode.HOME:
9667 case $.ui.keyCode.SPACE:
9668 // Activate only, no collapsing
9669 event.preventDefault();
9670 clearTimeout( this.activating );
9671 this._activate( selectedIndex );
9673 case $.ui.keyCode.ENTER:
9674 // Toggle (cancel delayed activation, allow collapsing)
9675 event.preventDefault();
9676 clearTimeout( this.activating );
9677 // Determine if we should collapse or activate
9678 this._activate( selectedIndex === this.options.active ? false : selectedIndex );
9684 // Focus the appropriate tab, based on which key was pressed
9685 event.preventDefault();
9686 clearTimeout( this.activating );
9687 selectedIndex = this._focusNextTab( selectedIndex, goingForward );
9689 // Navigating with control/command key will prevent automatic activation
9690 if ( !event.ctrlKey && !event.metaKey ) {
9692 // Update aria-selected immediately so that AT think the tab is already selected.
9693 // Otherwise AT may confuse the user by stating that they need to activate the tab,
9694 // but the tab will already be activated by the time the announcement finishes.
9695 focusedTab.attr( "aria-selected", "false" );
9696 this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
9698 this.activating = this._delay(function() {
9699 this.option( "active", selectedIndex );
9704 _panelKeydown: function( event ) {
9705 if ( this._handlePageNav( event ) ) {
9709 // Ctrl+up moves focus to the current tab
9710 if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
9711 event.preventDefault();
9712 this.active.focus();
9716 // Alt+page up/down moves focus to the previous/next tab (and activates)
9717 _handlePageNav: function( event ) {
9718 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
9719 this._activate( this._focusNextTab( this.options.active - 1, false ) );
9722 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
9723 this._activate( this._focusNextTab( this.options.active + 1, true ) );
9728 _findNextTab: function( index, goingForward ) {
9729 var lastTabIndex = this.tabs.length - 1;
9731 function constrain() {
9732 if ( index > lastTabIndex ) {
9736 index = lastTabIndex;
9741 while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
9742 index = goingForward ? index + 1 : index - 1;
9748 _focusNextTab: function( index, goingForward ) {
9749 index = this._findNextTab( index, goingForward );
9750 this.tabs.eq( index ).focus();
9754 _setOption: function( key, value ) {
9755 if ( key === "active" ) {
9756 // _activate() will handle invalid values and update this.options
9757 this._activate( value );
9761 if ( key === "disabled" ) {
9762 // don't use the widget factory's disabled handling
9763 this._setupDisabled( value );
9767 this._super( key, value);
9769 if ( key === "collapsible" ) {
9770 this.element.toggleClass( "ui-tabs-collapsible", value );
9771 // Setting collapsible: false while collapsed; open first panel
9772 if ( !value && this.options.active === false ) {
9773 this._activate( 0 );
9777 if ( key === "event" ) {
9778 this._setupEvents( value );
9781 if ( key === "heightStyle" ) {
9782 this._setupHeightStyle( value );
9786 _sanitizeSelector: function( hash ) {
9787 return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
9790 refresh: function() {
9791 var options = this.options,
9792 lis = this.tablist.children( ":has(a[href])" );
9794 // get disabled tabs from class attribute from HTML
9795 // this will get converted to a boolean if needed in _refresh()
9796 options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
9797 return lis.index( tab );
9800 this._processTabs();
9802 // was collapsed or no tabs
9803 if ( options.active === false || !this.anchors.length ) {
9804 options.active = false;
9806 // was active, but active tab is gone
9807 } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
9808 // all remaining tabs are disabled
9809 if ( this.tabs.length === options.disabled.length ) {
9810 options.active = false;
9812 // activate previous tab
9814 this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
9816 // was active, active tab still exists
9818 // make sure active index is correct
9819 options.active = this.tabs.index( this.active );
9825 _refresh: function() {
9826 this._setupDisabled( this.options.disabled );
9827 this._setupEvents( this.options.event );
9828 this._setupHeightStyle( this.options.heightStyle );
9830 this.tabs.not( this.active ).attr({
9831 "aria-selected": "false",
9832 "aria-expanded": "false",
9835 this.panels.not( this._getPanelForTab( this.active ) )
9838 "aria-hidden": "true"
9841 // Make sure one tab is in the tab order
9842 if ( !this.active.length ) {
9843 this.tabs.eq( 0 ).attr( "tabIndex", 0 );
9846 .addClass( "ui-tabs-active ui-state-active" )
9848 "aria-selected": "true",
9849 "aria-expanded": "true",
9852 this._getPanelForTab( this.active )
9855 "aria-hidden": "false"
9860 _processTabs: function() {
9862 prevTabs = this.tabs,
9863 prevAnchors = this.anchors,
9864 prevPanels = this.panels;
9866 this.tablist = this._getList()
9867 .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
9868 .attr( "role", "tablist" )
9870 // Prevent users from focusing disabled tabs via click
9871 .delegate( "> li", "mousedown" + this.eventNamespace, function( event ) {
9872 if ( $( this ).is( ".ui-state-disabled" ) ) {
9873 event.preventDefault();
9878 // Preventing the default action in mousedown doesn't prevent IE
9879 // from focusing the element, so if the anchor gets focused, blur.
9880 // We don't have to worry about focusing the previously focused
9881 // element since clicking on a non-focusable element should focus
9883 .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() {
9884 if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
9889 this.tabs = this.tablist.find( "> li:has(a[href])" )
9890 .addClass( "ui-state-default ui-corner-top" )
9896 this.anchors = this.tabs.map(function() {
9897 return $( "a", this )[ 0 ];
9899 .addClass( "ui-tabs-anchor" )
9901 role: "presentation",
9907 this.anchors.each(function( i, anchor ) {
9908 var selector, panel, panelId,
9909 anchorId = $( anchor ).uniqueId().attr( "id" ),
9910 tab = $( anchor ).closest( "li" ),
9911 originalAriaControls = tab.attr( "aria-controls" );
9914 if ( that._isLocal( anchor ) ) {
9915 selector = anchor.hash;
9916 panelId = selector.substring( 1 );
9917 panel = that.element.find( that._sanitizeSelector( selector ) );
9920 // If the tab doesn't already have aria-controls,
9921 // generate an id by using a throw-away element
9922 panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id;
9923 selector = "#" + panelId;
9924 panel = that.element.find( selector );
9925 if ( !panel.length ) {
9926 panel = that._createPanel( panelId );
9927 panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
9929 panel.attr( "aria-live", "polite" );
9932 if ( panel.length) {
9933 that.panels = that.panels.add( panel );
9935 if ( originalAriaControls ) {
9936 tab.data( "ui-tabs-aria-controls", originalAriaControls );
9939 "aria-controls": panelId,
9940 "aria-labelledby": anchorId
9942 panel.attr( "aria-labelledby", anchorId );
9946 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
9947 .attr( "role", "tabpanel" );
9949 // Avoid memory leaks (#10056)
9951 this._off( prevTabs.not( this.tabs ) );
9952 this._off( prevAnchors.not( this.anchors ) );
9953 this._off( prevPanels.not( this.panels ) );
9957 // allow overriding how to find the list for rare usage scenarios (#7715)
9958 _getList: function() {
9959 return this.tablist || this.element.find( "ol,ul" ).eq( 0 );
9962 _createPanel: function( id ) {
9965 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
9966 .data( "ui-tabs-destroy", true );
9969 _setupDisabled: function( disabled ) {
9970 if ( $.isArray( disabled ) ) {
9971 if ( !disabled.length ) {
9973 } else if ( disabled.length === this.anchors.length ) {
9979 for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) {
9980 if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
9982 .addClass( "ui-state-disabled" )
9983 .attr( "aria-disabled", "true" );
9986 .removeClass( "ui-state-disabled" )
9987 .removeAttr( "aria-disabled" );
9991 this.options.disabled = disabled;
9994 _setupEvents: function( event ) {
9997 $.each( event.split(" "), function( index, eventName ) {
9998 events[ eventName ] = "_eventHandler";
10002 this._off( this.anchors.add( this.tabs ).add( this.panels ) );
10003 // Always prevent the default action, even when disabled
10004 this._on( true, this.anchors, {
10005 click: function( event ) {
10006 event.preventDefault();
10009 this._on( this.anchors, events );
10010 this._on( this.tabs, { keydown: "_tabKeydown" } );
10011 this._on( this.panels, { keydown: "_panelKeydown" } );
10013 this._focusable( this.tabs );
10014 this._hoverable( this.tabs );
10017 _setupHeightStyle: function( heightStyle ) {
10019 parent = this.element.parent();
10021 if ( heightStyle === "fill" ) {
10022 maxHeight = parent.height();
10023 maxHeight -= this.element.outerHeight() - this.element.height();
10025 this.element.siblings( ":visible" ).each(function() {
10026 var elem = $( this ),
10027 position = elem.css( "position" );
10029 if ( position === "absolute" || position === "fixed" ) {
10032 maxHeight -= elem.outerHeight( true );
10035 this.element.children().not( this.panels ).each(function() {
10036 maxHeight -= $( this ).outerHeight( true );
10039 this.panels.each(function() {
10040 $( this ).height( Math.max( 0, maxHeight -
10041 $( this ).innerHeight() + $( this ).height() ) );
10043 .css( "overflow", "auto" );
10044 } else if ( heightStyle === "auto" ) {
10046 this.panels.each(function() {
10047 maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
10048 }).height( maxHeight );
10052 _eventHandler: function( event ) {
10053 var options = this.options,
10054 active = this.active,
10055 anchor = $( event.currentTarget ),
10056 tab = anchor.closest( "li" ),
10057 clickedIsActive = tab[ 0 ] === active[ 0 ],
10058 collapsing = clickedIsActive && options.collapsible,
10059 toShow = collapsing ? $() : this._getPanelForTab( tab ),
10060 toHide = !active.length ? $() : this._getPanelForTab( active ),
10064 newTab: collapsing ? $() : tab,
10068 event.preventDefault();
10070 if ( tab.hasClass( "ui-state-disabled" ) ||
10071 // tab is already loading
10072 tab.hasClass( "ui-tabs-loading" ) ||
10073 // can't switch durning an animation
10075 // click on active header, but not collapsible
10076 ( clickedIsActive && !options.collapsible ) ||
10077 // allow canceling activation
10078 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
10082 options.active = collapsing ? false : this.tabs.index( tab );
10084 this.active = clickedIsActive ? $() : tab;
10089 if ( !toHide.length && !toShow.length ) {
10090 $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
10093 if ( toShow.length ) {
10094 this.load( this.tabs.index( tab ), event );
10096 this._toggle( event, eventData );
10099 // handles show/hide for selecting tabs
10100 _toggle: function( event, eventData ) {
10102 toShow = eventData.newPanel,
10103 toHide = eventData.oldPanel;
10105 this.running = true;
10107 function complete() {
10108 that.running = false;
10109 that._trigger( "activate", event, eventData );
10113 eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" );
10115 if ( toShow.length && that.options.show ) {
10116 that._show( toShow, that.options.show, complete );
10123 // start out by hiding, then showing, then completing
10124 if ( toHide.length && this.options.hide ) {
10125 this._hide( toHide, this.options.hide, function() {
10126 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
10130 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
10135 toHide.attr( "aria-hidden", "true" );
10136 eventData.oldTab.attr({
10137 "aria-selected": "false",
10138 "aria-expanded": "false"
10140 // If we're switching tabs, remove the old tab from the tab order.
10141 // If we're opening from collapsed state, remove the previous tab from the tab order.
10142 // If we're collapsing, then keep the collapsing tab in the tab order.
10143 if ( toShow.length && toHide.length ) {
10144 eventData.oldTab.attr( "tabIndex", -1 );
10145 } else if ( toShow.length ) {
10146 this.tabs.filter(function() {
10147 return $( this ).attr( "tabIndex" ) === 0;
10149 .attr( "tabIndex", -1 );
10152 toShow.attr( "aria-hidden", "false" );
10153 eventData.newTab.attr({
10154 "aria-selected": "true",
10155 "aria-expanded": "true",
10160 _activate: function( index ) {
10162 active = this._findActive( index );
10164 // trying to activate the already active panel
10165 if ( active[ 0 ] === this.active[ 0 ] ) {
10169 // trying to collapse, simulate a click on the current active header
10170 if ( !active.length ) {
10171 active = this.active;
10174 anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
10175 this._eventHandler({
10177 currentTarget: anchor,
10178 preventDefault: $.noop
10182 _findActive: function( index ) {
10183 return index === false ? $() : this.tabs.eq( index );
10186 _getIndex: function( index ) {
10187 // meta-function to give users option to provide a href string instead of a numerical index.
10188 if ( typeof index === "string" ) {
10189 index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) );
10195 _destroy: function() {
10200 this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" );
10203 .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
10204 .removeAttr( "role" );
10207 .removeClass( "ui-tabs-anchor" )
10208 .removeAttr( "role" )
10209 .removeAttr( "tabIndex" )
10212 this.tablist.unbind( this.eventNamespace );
10214 this.tabs.add( this.panels ).each(function() {
10215 if ( $.data( this, "ui-tabs-destroy" ) ) {
10216 $( this ).remove();
10219 .removeClass( "ui-state-default ui-state-active ui-state-disabled " +
10220 "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" )
10221 .removeAttr( "tabIndex" )
10222 .removeAttr( "aria-live" )
10223 .removeAttr( "aria-busy" )
10224 .removeAttr( "aria-selected" )
10225 .removeAttr( "aria-labelledby" )
10226 .removeAttr( "aria-hidden" )
10227 .removeAttr( "aria-expanded" )
10228 .removeAttr( "role" );
10232 this.tabs.each(function() {
10233 var li = $( this ),
10234 prev = li.data( "ui-tabs-aria-controls" );
10237 .attr( "aria-controls", prev )
10238 .removeData( "ui-tabs-aria-controls" );
10240 li.removeAttr( "aria-controls" );
10244 this.panels.show();
10246 if ( this.options.heightStyle !== "content" ) {
10247 this.panels.css( "height", "" );
10251 enable: function( index ) {
10252 var disabled = this.options.disabled;
10253 if ( disabled === false ) {
10257 if ( index === undefined ) {
10260 index = this._getIndex( index );
10261 if ( $.isArray( disabled ) ) {
10262 disabled = $.map( disabled, function( num ) {
10263 return num !== index ? num : null;
10266 disabled = $.map( this.tabs, function( li, num ) {
10267 return num !== index ? num : null;
10271 this._setupDisabled( disabled );
10274 disable: function( index ) {
10275 var disabled = this.options.disabled;
10276 if ( disabled === true ) {
10280 if ( index === undefined ) {
10283 index = this._getIndex( index );
10284 if ( $.inArray( index, disabled ) !== -1 ) {
10287 if ( $.isArray( disabled ) ) {
10288 disabled = $.merge( [ index ], disabled ).sort();
10290 disabled = [ index ];
10293 this._setupDisabled( disabled );
10296 load: function( index, event ) {
10297 index = this._getIndex( index );
10299 tab = this.tabs.eq( index ),
10300 anchor = tab.find( ".ui-tabs-anchor" ),
10301 panel = this._getPanelForTab( tab ),
10306 complete = function( jqXHR, status ) {
10307 if ( status === "abort" ) {
10308 that.panels.stop( false, true );
10311 tab.removeClass( "ui-tabs-loading" );
10312 panel.removeAttr( "aria-busy" );
10314 if ( jqXHR === that.xhr ) {
10320 if ( this._isLocal( anchor[ 0 ] ) ) {
10324 this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
10326 // support: jQuery <1.8
10327 // jQuery <1.8 returns false if the request is canceled in beforeSend,
10328 // but as of 1.8, $.ajax() always returns a jqXHR object.
10329 if ( this.xhr && this.xhr.statusText !== "canceled" ) {
10330 tab.addClass( "ui-tabs-loading" );
10331 panel.attr( "aria-busy", "true" );
10334 .done(function( response, status, jqXHR ) {
10335 // support: jQuery <1.8
10336 // http://bugs.jquery.com/ticket/11778
10337 setTimeout(function() {
10338 panel.html( response );
10339 that._trigger( "load", event, eventData );
10341 complete( jqXHR, status );
10344 .fail(function( jqXHR, status ) {
10345 // support: jQuery <1.8
10346 // http://bugs.jquery.com/ticket/11778
10347 setTimeout(function() {
10348 complete( jqXHR, status );
10354 _ajaxSettings: function( anchor, event, eventData ) {
10357 url: anchor.attr( "href" ),
10358 beforeSend: function( jqXHR, settings ) {
10359 return that._trigger( "beforeLoad", event,
10360 $.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) );
10365 _getPanelForTab: function( tab ) {
10366 var id = $( tab ).attr( "aria-controls" );
10367 return this.element.find( this._sanitizeSelector( "#" + id ) );
10373 * jQuery UI Effects 1.11.4
10374 * http://jqueryui.com
10376 * Copyright jQuery Foundation and other contributors
10377 * Released under the MIT license.
10378 * http://jquery.org/license
10380 * http://api.jqueryui.com/category/effects-core/
10384 var dataSpace = "ui-effects-",
10386 // Create a local jQuery because jQuery Color relies on it and the
10387 // global may not exist with AMD and a custom build (#10199)
10395 * jQuery Color Animations v2.1.2
10396 * https://github.com/jquery/jquery-color
10398 * Copyright 2014 jQuery Foundation and other contributors
10399 * Released under the MIT license.
10400 * http://jquery.org/license
10402 * Date: Wed Jan 16 08:47:09 2013 -0600
10404 (function( jQuery, undefined ) {
10406 var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
10408 // plusequals test for += 100 -= 100
10409 rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
10410 // a set of RE's that can match strings and generate color tuples.
10411 stringParsers = [ {
10412 re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
10413 parse: function( execResult ) {
10422 re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
10423 parse: function( execResult ) {
10425 execResult[ 1 ] * 2.55,
10426 execResult[ 2 ] * 2.55,
10427 execResult[ 3 ] * 2.55,
10432 // this regex ignores A-F because it's compared against an already lowercased string
10433 re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
10434 parse: function( execResult ) {
10436 parseInt( execResult[ 1 ], 16 ),
10437 parseInt( execResult[ 2 ], 16 ),
10438 parseInt( execResult[ 3 ], 16 )
10442 // this regex ignores A-F because it's compared against an already lowercased string
10443 re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
10444 parse: function( execResult ) {
10446 parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
10447 parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
10448 parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
10452 re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
10454 parse: function( execResult ) {
10457 execResult[ 2 ] / 100,
10458 execResult[ 3 ] / 100,
10465 color = jQuery.Color = function( color, green, blue, alpha ) {
10466 return new jQuery.Color.fn.parse( color, green, blue, alpha );
10516 support = color.support = {},
10518 // element for support tests
10519 supportElem = jQuery( "<p>" )[ 0 ],
10521 // colors = jQuery.Color.names
10524 // local aliases of functions called often
10525 each = jQuery.each;
10527 // determine rgba support immediately
10528 supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
10529 support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
10531 // define cache name and alpha properties
10532 // for rgba and hsla spaces
10533 each( spaces, function( spaceName, space ) {
10534 space.cache = "_" + spaceName;
10535 space.props.alpha = {
10542 function clamp( value, prop, allowEmpty ) {
10543 var type = propTypes[ prop.type ] || {};
10545 if ( value == null ) {
10546 return (allowEmpty || !prop.def) ? null : prop.def;
10549 // ~~ is an short way of doing floor for positive numbers
10550 value = type.floor ? ~~value : parseFloat( value );
10552 // IE will pass in empty strings as value for alpha,
10553 // which will hit this case
10554 if ( isNaN( value ) ) {
10559 // we add mod before modding to make sure that negatives values
10560 // get converted properly: -10 -> 350
10561 return (value + type.mod) % type.mod;
10564 // for now all property types without mod have min and max
10565 return 0 > value ? 0 : type.max < value ? type.max : value;
10568 function stringParse( string ) {
10569 var inst = color(),
10570 rgba = inst._rgba = [];
10572 string = string.toLowerCase();
10574 each( stringParsers, function( i, parser ) {
10576 match = parser.re.exec( string ),
10577 values = match && parser.parse( match ),
10578 spaceName = parser.space || "rgba";
10581 parsed = inst[ spaceName ]( values );
10583 // if this was an rgba parse the assignment might happen twice
10585 inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
10586 rgba = inst._rgba = parsed._rgba;
10588 // exit each( stringParsers ) here because we matched
10593 // Found a stringParser that handled it
10594 if ( rgba.length ) {
10596 // if this came from a parsed string, force "transparent" when alpha is 0
10597 // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
10598 if ( rgba.join() === "0,0,0,0" ) {
10599 jQuery.extend( rgba, colors.transparent );
10605 return colors[ string ];
10608 color.fn = jQuery.extend( color.prototype, {
10609 parse: function( red, green, blue, alpha ) {
10610 if ( red === undefined ) {
10611 this._rgba = [ null, null, null, null ];
10614 if ( red.jquery || red.nodeType ) {
10615 red = jQuery( red ).css( green );
10620 type = jQuery.type( red ),
10621 rgba = this._rgba = [];
10623 // more than 1 argument specified - assume ( red, green, blue, alpha )
10624 if ( green !== undefined ) {
10625 red = [ red, green, blue, alpha ];
10629 if ( type === "string" ) {
10630 return this.parse( stringParse( red ) || colors._default );
10633 if ( type === "array" ) {
10634 each( spaces.rgba.props, function( key, prop ) {
10635 rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
10640 if ( type === "object" ) {
10641 if ( red instanceof color ) {
10642 each( spaces, function( spaceName, space ) {
10643 if ( red[ space.cache ] ) {
10644 inst[ space.cache ] = red[ space.cache ].slice();
10648 each( spaces, function( spaceName, space ) {
10649 var cache = space.cache;
10650 each( space.props, function( key, prop ) {
10652 // if the cache doesn't exist, and we know how to convert
10653 if ( !inst[ cache ] && space.to ) {
10655 // if the value was null, we don't need to copy it
10656 // if the key was alpha, we don't need to copy it either
10657 if ( key === "alpha" || red[ key ] == null ) {
10660 inst[ cache ] = space.to( inst._rgba );
10663 // this is the only case where we allow nulls for ALL properties.
10664 // call clamp with alwaysAllowEmpty
10665 inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
10668 // everything defined but alpha?
10669 if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
10670 // use the default of 1
10671 inst[ cache ][ 3 ] = 1;
10672 if ( space.from ) {
10673 inst._rgba = space.from( inst[ cache ] );
10681 is: function( compare ) {
10682 var is = color( compare ),
10686 each( spaces, function( _, space ) {
10688 isCache = is[ space.cache ];
10690 localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
10691 each( space.props, function( _, prop ) {
10692 if ( isCache[ prop.idx ] != null ) {
10693 same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
10702 _space: function() {
10705 each( spaces, function( spaceName, space ) {
10706 if ( inst[ space.cache ] ) {
10707 used.push( spaceName );
10712 transition: function( other, distance ) {
10713 var end = color( other ),
10714 spaceName = end._space(),
10715 space = spaces[ spaceName ],
10716 startColor = this.alpha() === 0 ? color( "transparent" ) : this,
10717 start = startColor[ space.cache ] || space.to( startColor._rgba ),
10718 result = start.slice();
10720 end = end[ space.cache ];
10721 each( space.props, function( key, prop ) {
10722 var index = prop.idx,
10723 startValue = start[ index ],
10724 endValue = end[ index ],
10725 type = propTypes[ prop.type ] || {};
10727 // if null, don't override start value
10728 if ( endValue === null ) {
10731 // if null - use end
10732 if ( startValue === null ) {
10733 result[ index ] = endValue;
10736 if ( endValue - startValue > type.mod / 2 ) {
10737 startValue += type.mod;
10738 } else if ( startValue - endValue > type.mod / 2 ) {
10739 startValue -= type.mod;
10742 result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
10745 return this[ spaceName ]( result );
10747 blend: function( opaque ) {
10748 // if we are already opaque - return ourself
10749 if ( this._rgba[ 3 ] === 1 ) {
10753 var rgb = this._rgba.slice(),
10755 blend = color( opaque )._rgba;
10757 return color( jQuery.map( rgb, function( v, i ) {
10758 return ( 1 - a ) * blend[ i ] + a * v;
10761 toRgbaString: function() {
10762 var prefix = "rgba(",
10763 rgba = jQuery.map( this._rgba, function( v, i ) {
10764 return v == null ? ( i > 2 ? 1 : 0 ) : v;
10767 if ( rgba[ 3 ] === 1 ) {
10772 return prefix + rgba.join() + ")";
10774 toHslaString: function() {
10775 var prefix = "hsla(",
10776 hsla = jQuery.map( this.hsla(), function( v, i ) {
10782 if ( i && i < 3 ) {
10783 v = Math.round( v * 100 ) + "%";
10788 if ( hsla[ 3 ] === 1 ) {
10792 return prefix + hsla.join() + ")";
10794 toHexString: function( includeAlpha ) {
10795 var rgba = this._rgba.slice(),
10796 alpha = rgba.pop();
10798 if ( includeAlpha ) {
10799 rgba.push( ~~( alpha * 255 ) );
10802 return "#" + jQuery.map( rgba, function( v ) {
10804 // default to 0 when nulls exist
10805 v = ( v || 0 ).toString( 16 );
10806 return v.length === 1 ? "0" + v : v;
10809 toString: function() {
10810 return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
10813 color.fn.parse.prototype = color.fn;
10815 // hsla conversions adapted from:
10816 // https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
10818 function hue2rgb( p, q, h ) {
10821 return p + ( q - p ) * h * 6;
10827 return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6;
10832 spaces.hsla.to = function( rgba ) {
10833 if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
10834 return [ null, null, null, rgba[ 3 ] ];
10836 var r = rgba[ 0 ] / 255,
10837 g = rgba[ 1 ] / 255,
10838 b = rgba[ 2 ] / 255,
10840 max = Math.max( r, g, b ),
10841 min = Math.min( r, g, b ),
10847 if ( min === max ) {
10849 } else if ( r === max ) {
10850 h = ( 60 * ( g - b ) / diff ) + 360;
10851 } else if ( g === max ) {
10852 h = ( 60 * ( b - r ) / diff ) + 120;
10854 h = ( 60 * ( r - g ) / diff ) + 240;
10857 // chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
10858 // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
10859 if ( diff === 0 ) {
10861 } else if ( l <= 0.5 ) {
10864 s = diff / ( 2 - add );
10866 return [ Math.round(h) % 360, s, l, a == null ? 1 : a ];
10869 spaces.hsla.from = function( hsla ) {
10870 if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
10871 return [ null, null, null, hsla[ 3 ] ];
10873 var h = hsla[ 0 ] / 360,
10877 q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
10881 Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
10882 Math.round( hue2rgb( p, q, h ) * 255 ),
10883 Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
10888 each( spaces, function( spaceName, space ) {
10889 var props = space.props,
10890 cache = space.cache,
10894 // makes rgba() and hsla()
10895 color.fn[ spaceName ] = function( value ) {
10897 // generate a cache for this space if it doesn't exist
10898 if ( to && !this[ cache ] ) {
10899 this[ cache ] = to( this._rgba );
10901 if ( value === undefined ) {
10902 return this[ cache ].slice();
10906 type = jQuery.type( value ),
10907 arr = ( type === "array" || type === "object" ) ? value : arguments,
10908 local = this[ cache ].slice();
10910 each( props, function( key, prop ) {
10911 var val = arr[ type === "object" ? key : prop.idx ];
10912 if ( val == null ) {
10913 val = local[ prop.idx ];
10915 local[ prop.idx ] = clamp( val, prop );
10919 ret = color( from( local ) );
10920 ret[ cache ] = local;
10923 return color( local );
10927 // makes red() green() blue() alpha() hue() saturation() lightness()
10928 each( props, function( key, prop ) {
10929 // alpha is included in more than one space
10930 if ( color.fn[ key ] ) {
10933 color.fn[ key ] = function( value ) {
10934 var vtype = jQuery.type( value ),
10935 fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
10936 local = this[ fn ](),
10937 cur = local[ prop.idx ],
10940 if ( vtype === "undefined" ) {
10944 if ( vtype === "function" ) {
10945 value = value.call( this, cur );
10946 vtype = jQuery.type( value );
10948 if ( value == null && prop.empty ) {
10951 if ( vtype === "string" ) {
10952 match = rplusequals.exec( value );
10954 value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
10957 local[ prop.idx ] = value;
10958 return this[ fn ]( local );
10963 // add cssHook and .fx.step function for each named hook.
10964 // accept a space separated string of properties
10965 color.hook = function( hook ) {
10966 var hooks = hook.split( " " );
10967 each( hooks, function( i, hook ) {
10968 jQuery.cssHooks[ hook ] = {
10969 set: function( elem, value ) {
10970 var parsed, curElem,
10971 backgroundColor = "";
10973 if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) {
10974 value = color( parsed || value );
10975 if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
10976 curElem = hook === "backgroundColor" ? elem.parentNode : elem;
10978 (backgroundColor === "" || backgroundColor === "transparent") &&
10979 curElem && curElem.style
10982 backgroundColor = jQuery.css( curElem, "backgroundColor" );
10983 curElem = curElem.parentNode;
10988 value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
10993 value = value.toRgbaString();
10996 elem.style[ hook ] = value;
10998 // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit'
11002 jQuery.fx.step[ hook ] = function( fx ) {
11003 if ( !fx.colorInit ) {
11004 fx.start = color( fx.elem, hook );
11005 fx.end = color( fx.end );
11006 fx.colorInit = true;
11008 jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
11014 color.hook( stepHooks );
11016 jQuery.cssHooks.borderColor = {
11017 expand: function( value ) {
11020 each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
11021 expanded[ "border" + part + "Color" ] = value;
11027 // Basic color names only.
11028 // Usage of any of the other color names requires adding yourself or including
11029 // jquery.color.svg-names.js.
11030 colors = jQuery.Color.names = {
11031 // 4.1. Basic color keywords
11035 fuchsia: "#ff00ff",
11049 // 4.2.3. "transparent" color keyword
11050 transparent: [ null, null, null, 0 ],
11052 _default: "#ffffff"
11057 /******************************************************************************/
11058 /****************************** CLASS ANIMATIONS ******************************/
11059 /******************************************************************************/
11062 var classAnimationActions = [ "add", "remove", "toggle" ],
11063 shorthandStyles = {
11075 $.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) {
11076 $.fx.step[ prop ] = function( fx ) {
11077 if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
11078 jQuery.style( fx.elem, prop, fx.end );
11084 function getElementStyles( elem ) {
11086 style = elem.ownerDocument.defaultView ?
11087 elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :
11091 if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
11092 len = style.length;
11094 key = style[ len ];
11095 if ( typeof style[ key ] === "string" ) {
11096 styles[ $.camelCase( key ) ] = style[ key ];
11099 // support: Opera, IE <9
11101 for ( key in style ) {
11102 if ( typeof style[ key ] === "string" ) {
11103 styles[ key ] = style[ key ];
11111 function styleDifference( oldStyle, newStyle ) {
11115 for ( name in newStyle ) {
11116 value = newStyle[ name ];
11117 if ( oldStyle[ name ] !== value ) {
11118 if ( !shorthandStyles[ name ] ) {
11119 if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
11120 diff[ name ] = value;
11129 // support: jQuery <1.8
11130 if ( !$.fn.addBack ) {
11131 $.fn.addBack = function( selector ) {
11132 return this.add( selector == null ?
11133 this.prevObject : this.prevObject.filter( selector )
11138 $.effects.animateClass = function( value, duration, easing, callback ) {
11139 var o = $.speed( duration, easing, callback );
11141 return this.queue( function() {
11142 var animated = $( this ),
11143 baseClass = animated.attr( "class" ) || "",
11145 allAnimations = o.children ? animated.find( "*" ).addBack() : animated;
11147 // map the animated objects to store the original styles.
11148 allAnimations = allAnimations.map(function() {
11149 var el = $( this );
11152 start: getElementStyles( this )
11156 // apply class change
11157 applyClassChange = function() {
11158 $.each( classAnimationActions, function(i, action) {
11159 if ( value[ action ] ) {
11160 animated[ action + "Class" ]( value[ action ] );
11164 applyClassChange();
11166 // map all animated objects again - calculate new styles and diff
11167 allAnimations = allAnimations.map(function() {
11168 this.end = getElementStyles( this.el[ 0 ] );
11169 this.diff = styleDifference( this.start, this.end );
11173 // apply original class
11174 animated.attr( "class", baseClass );
11176 // map all animated objects again - this time collecting a promise
11177 allAnimations = allAnimations.map(function() {
11178 var styleInfo = this,
11179 dfd = $.Deferred(),
11180 opts = $.extend({}, o, {
11182 complete: function() {
11183 dfd.resolve( styleInfo );
11187 this.el.animate( this.diff, opts );
11188 return dfd.promise();
11191 // once all animations have completed:
11192 $.when.apply( $, allAnimations.get() ).done(function() {
11194 // set the final class
11195 applyClassChange();
11197 // for each animated element,
11198 // clear all css properties that were animated
11199 $.each( arguments, function() {
11201 $.each( this.diff, function(key) {
11206 // this is guarnteed to be there if you use jQuery.speed()
11207 // it also handles dequeuing the next anim...
11208 o.complete.call( animated[ 0 ] );
11214 addClass: (function( orig ) {
11215 return function( classNames, speed, easing, callback ) {
11217 $.effects.animateClass.call( this,
11218 { add: classNames }, speed, easing, callback ) :
11219 orig.apply( this, arguments );
11221 })( $.fn.addClass ),
11223 removeClass: (function( orig ) {
11224 return function( classNames, speed, easing, callback ) {
11225 return arguments.length > 1 ?
11226 $.effects.animateClass.call( this,
11227 { remove: classNames }, speed, easing, callback ) :
11228 orig.apply( this, arguments );
11230 })( $.fn.removeClass ),
11232 toggleClass: (function( orig ) {
11233 return function( classNames, force, speed, easing, callback ) {
11234 if ( typeof force === "boolean" || force === undefined ) {
11236 // without speed parameter
11237 return orig.apply( this, arguments );
11239 return $.effects.animateClass.call( this,
11240 (force ? { add: classNames } : { remove: classNames }),
11241 speed, easing, callback );
11244 // without force parameter
11245 return $.effects.animateClass.call( this,
11246 { toggle: classNames }, force, speed, easing );
11249 })( $.fn.toggleClass ),
11251 switchClass: function( remove, add, speed, easing, callback) {
11252 return $.effects.animateClass.call( this, {
11255 }, speed, easing, callback );
11261 /******************************************************************************/
11262 /*********************************** EFFECTS **********************************/
11263 /******************************************************************************/
11267 $.extend( $.effects, {
11270 // Saves a set of properties in a data storage
11271 save: function( element, set ) {
11272 for ( var i = 0; i < set.length; i++ ) {
11273 if ( set[ i ] !== null ) {
11274 element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
11279 // Restores a set of previously saved properties from a data storage
11280 restore: function( element, set ) {
11282 for ( i = 0; i < set.length; i++ ) {
11283 if ( set[ i ] !== null ) {
11284 val = element.data( dataSpace + set[ i ] );
11285 // support: jQuery 1.6.2
11286 // http://bugs.jquery.com/ticket/9917
11287 // jQuery 1.6.2 incorrectly returns undefined for any falsy value.
11288 // We can't differentiate between "" and 0 here, so we just assume
11289 // empty string since it's likely to be a more common value...
11290 if ( val === undefined ) {
11293 element.css( set[ i ], val );
11298 setMode: function( el, mode ) {
11299 if (mode === "toggle") {
11300 mode = el.is( ":hidden" ) ? "show" : "hide";
11305 // Translates a [top,left] array into a baseline value
11306 // this should be a little more flexible in the future to handle a string & hash
11307 getBaseline: function( origin, original ) {
11309 switch ( origin[ 0 ] ) {
11310 case "top": y = 0; break;
11311 case "middle": y = 0.5; break;
11312 case "bottom": y = 1; break;
11313 default: y = origin[ 0 ] / original.height;
11315 switch ( origin[ 1 ] ) {
11316 case "left": x = 0; break;
11317 case "center": x = 0.5; break;
11318 case "right": x = 1; break;
11319 default: x = origin[ 1 ] / original.width;
11327 // Wraps the element around a wrapper that copies position properties
11328 createWrapper: function( element ) {
11330 // if the element is already wrapped, return it
11331 if ( element.parent().is( ".ui-effects-wrapper" )) {
11332 return element.parent();
11335 // wrap the element
11337 width: element.outerWidth(true),
11338 height: element.outerHeight(true),
11339 "float": element.css( "float" )
11341 wrapper = $( "<div></div>" )
11342 .addClass( "ui-effects-wrapper" )
11345 background: "transparent",
11350 // Store the size in case width/height are defined in % - Fixes #5245
11352 width: element.width(),
11353 height: element.height()
11355 active = document.activeElement;
11357 // support: Firefox
11358 // Firefox incorrectly exposes anonymous content
11359 // https://bugzilla.mozilla.org/show_bug.cgi?id=561664
11363 active = document.body;
11366 element.wrap( wrapper );
11368 // Fixes #7595 - Elements lose focus when wrapped.
11369 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
11370 $( active ).focus();
11373 wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element
11375 // transfer positioning properties to the wrapper
11376 if ( element.css( "position" ) === "static" ) {
11377 wrapper.css({ position: "relative" });
11378 element.css({ position: "relative" });
11381 position: element.css( "position" ),
11382 zIndex: element.css( "z-index" )
11384 $.each([ "top", "left", "bottom", "right" ], function(i, pos) {
11385 props[ pos ] = element.css( pos );
11386 if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
11387 props[ pos ] = "auto";
11391 position: "relative",
11400 return wrapper.css( props ).show();
11403 removeWrapper: function( element ) {
11404 var active = document.activeElement;
11406 if ( element.parent().is( ".ui-effects-wrapper" ) ) {
11407 element.parent().replaceWith( element );
11409 // Fixes #7595 - Elements lose focus when wrapped.
11410 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
11411 $( active ).focus();
11418 setTransition: function( element, list, factor, value ) {
11419 value = value || {};
11420 $.each( list, function( i, x ) {
11421 var unit = element.cssUnit( x );
11422 if ( unit[ 0 ] > 0 ) {
11423 value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
11430 // return an effect options object for the given parameters:
11431 function _normalizeArguments( effect, options, speed, callback ) {
11433 // allow passing all options as the first parameter
11434 if ( $.isPlainObject( effect ) ) {
11436 effect = effect.effect;
11439 // convert to an object
11440 effect = { effect: effect };
11442 // catch (effect, null, ...)
11443 if ( options == null ) {
11447 // catch (effect, callback)
11448 if ( $.isFunction( options ) ) {
11449 callback = options;
11454 // catch (effect, speed, ?)
11455 if ( typeof options === "number" || $.fx.speeds[ options ] ) {
11461 // catch (effect, options, callback)
11462 if ( $.isFunction( speed ) ) {
11467 // add options to effect
11469 $.extend( effect, options );
11472 speed = speed || options.duration;
11473 effect.duration = $.fx.off ? 0 :
11474 typeof speed === "number" ? speed :
11475 speed in $.fx.speeds ? $.fx.speeds[ speed ] :
11476 $.fx.speeds._default;
11478 effect.complete = callback || options.complete;
11483 function standardAnimationOption( option ) {
11484 // Valid standard speeds (nothing, number, named speed)
11485 if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) {
11489 // Invalid strings - treat as "normal" speed
11490 if ( typeof option === "string" && !$.effects.effect[ option ] ) {
11494 // Complete callback
11495 if ( $.isFunction( option ) ) {
11499 // Options hash (but not naming an effect)
11500 if ( typeof option === "object" && !option.effect ) {
11504 // Didn't match any standard API
11509 effect: function( /* effect, options, speed, callback */ ) {
11510 var args = _normalizeArguments.apply( this, arguments ),
11512 queue = args.queue,
11513 effectMethod = $.effects.effect[ args.effect ];
11515 if ( $.fx.off || !effectMethod ) {
11516 // delegate to the original method (e.g., .show()) if possible
11518 return this[ mode ]( args.duration, args.complete );
11520 return this.each( function() {
11521 if ( args.complete ) {
11522 args.complete.call( this );
11528 function run( next ) {
11529 var elem = $( this ),
11530 complete = args.complete,
11534 if ( $.isFunction( complete ) ) {
11535 complete.call( elem[0] );
11537 if ( $.isFunction( next ) ) {
11542 // If the element already has the correct final state, delegate to
11543 // the core methods so the internal tracking of "olddisplay" works.
11544 if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
11548 effectMethod.call( elem[0], args, done );
11552 return queue === false ? this.each( run ) : this.queue( queue || "fx", run );
11555 show: (function( orig ) {
11556 return function( option ) {
11557 if ( standardAnimationOption( option ) ) {
11558 return orig.apply( this, arguments );
11560 var args = _normalizeArguments.apply( this, arguments );
11561 args.mode = "show";
11562 return this.effect.call( this, args );
11567 hide: (function( orig ) {
11568 return function( option ) {
11569 if ( standardAnimationOption( option ) ) {
11570 return orig.apply( this, arguments );
11572 var args = _normalizeArguments.apply( this, arguments );
11573 args.mode = "hide";
11574 return this.effect.call( this, args );
11579 toggle: (function( orig ) {
11580 return function( option ) {
11581 if ( standardAnimationOption( option ) || typeof option === "boolean" ) {
11582 return orig.apply( this, arguments );
11584 var args = _normalizeArguments.apply( this, arguments );
11585 args.mode = "toggle";
11586 return this.effect.call( this, args );
11591 // helper functions
11592 cssUnit: function(key) {
11593 var style = this.css( key ),
11596 $.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
11597 if ( style.indexOf( unit ) > 0 ) {
11598 val = [ parseFloat( style ), unit ];
11607 /******************************************************************************/
11608 /*********************************** EASING ***********************************/
11609 /******************************************************************************/
11613 // based on easing equations from Robert Penner (http://www.robertpenner.com/easing)
11615 var baseEasings = {};
11617 $.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
11618 baseEasings[ name ] = function( p ) {
11619 return Math.pow( p, i + 2 );
11623 $.extend( baseEasings, {
11624 Sine: function( p ) {
11625 return 1 - Math.cos( p * Math.PI / 2 );
11627 Circ: function( p ) {
11628 return 1 - Math.sqrt( 1 - p * p );
11630 Elastic: function( p ) {
11631 return p === 0 || p === 1 ? p :
11632 -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 );
11634 Back: function( p ) {
11635 return p * p * ( 3 * p - 2 );
11637 Bounce: function( p ) {
11641 while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
11642 return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
11646 $.each( baseEasings, function( name, easeIn ) {
11647 $.easing[ "easeIn" + name ] = easeIn;
11648 $.easing[ "easeOut" + name ] = function( p ) {
11649 return 1 - easeIn( 1 - p );
11651 $.easing[ "easeInOut" + name ] = function( p ) {
11653 easeIn( p * 2 ) / 2 :
11654 1 - easeIn( p * -2 + 2 ) / 2;
11660 var effect = $.effects;
11664 * jQuery UI Effects Highlight 1.11.4
11665 * http://jqueryui.com
11667 * Copyright jQuery Foundation and other contributors
11668 * Released under the MIT license.
11669 * http://jquery.org/license
11671 * http://api.jqueryui.com/highlight-effect/
11675 var effectHighlight = $.effects.effect.highlight = function( o, done ) {
11676 var elem = $( this ),
11677 props = [ "backgroundImage", "backgroundColor", "opacity" ],
11678 mode = $.effects.setMode( elem, o.mode || "show" ),
11680 backgroundColor: elem.css( "backgroundColor" )
11683 if (mode === "hide") {
11684 animation.opacity = 0;
11687 $.effects.save( elem, props );
11692 backgroundImage: "none",
11693 backgroundColor: o.color || "#ffff99"
11695 .animate( animation, {
11697 duration: o.duration,
11699 complete: function() {
11700 if ( mode === "hide" ) {
11703 $.effects.restore( elem, props );