1 /*! jQuery UI - v1.11.3 - 2015-03-01
3 * Includes: core.js, widget.js, mouse.js, position.js, draggable.js, droppable.js, resizable.js, selectable.js, sortable.js, accordion.js, autocomplete.js, button.js, datepicker.js, dialog.js, menu.js, progressbar.js, selectmenu.js, slider.js, spinner.js, tabs.js, tooltip.js, effect.js, effect-blind.js, effect-bounce.js, effect-clip.js, effect-drop.js, effect-explode.js, effect-fade.js, effect-fold.js, effect-highlight.js, effect-puff.js, effect-pulsate.js, effect-scale.js, effect-shake.js, effect-size.js, effect-slide.js, effect-transfer.js
4 * Copyright 2015 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.3
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.3
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.3
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.3
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.3
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 sortable.currentItem = ui.helper
2340 .appendTo( sortable.element )
2341 .data( "ui-sortable-item", true );
2343 // Store helper option to later restore it
2344 sortable.options._helper = sortable.options.helper;
2346 sortable.options.helper = function() {
2347 return ui.helper[ 0 ];
2350 // Fire the start events of the sortable with our passed browser event,
2351 // and our own helper (so it doesn't create a new one)
2352 event.target = sortable.currentItem[ 0 ];
2353 sortable._mouseCapture( event, true );
2354 sortable._mouseStart( event, true, true );
2356 // Because the browser event is way off the new appended portlet,
2357 // modify necessary variables to reflect the changes
2358 sortable.offset.click.top = draggable.offset.click.top;
2359 sortable.offset.click.left = draggable.offset.click.left;
2360 sortable.offset.parent.left -= draggable.offset.parent.left -
2361 sortable.offset.parent.left;
2362 sortable.offset.parent.top -= draggable.offset.parent.top -
2363 sortable.offset.parent.top;
2365 draggable._trigger( "toSortable", event );
2367 // Inform draggable that the helper is in a valid drop zone,
2368 // used solely in the revert option to handle "valid/invalid".
2369 draggable.dropped = sortable.element;
2371 // Need to refreshPositions of all sortables in the case that
2372 // adding to one sortable changes the location of the other sortables (#9675)
2373 $.each( draggable.sortables, function() {
2374 this.refreshPositions();
2377 // hack so receive/update callbacks work (mostly)
2378 draggable.currentItem = draggable.element;
2379 sortable.fromOutside = draggable;
2382 if ( sortable.currentItem ) {
2383 sortable._mouseDrag( event );
2384 // Copy the sortable's position because the draggable's can potentially reflect
2385 // a relative position, while sortable is always absolute, which the dragged
2386 // element has now become. (#8809)
2387 ui.position = sortable.position;
2390 // If it doesn't intersect with the sortable, and it intersected before,
2391 // we fake the drag stop of the sortable, but make sure it doesn't remove
2392 // the helper by using cancelHelperRemoval.
2393 if ( sortable.isOver ) {
2395 sortable.isOver = 0;
2396 sortable.cancelHelperRemoval = true;
2398 // Calling sortable's mouseStop would trigger a revert,
2399 // so revert must be temporarily false until after mouseStop is called.
2400 sortable.options._revert = sortable.options.revert;
2401 sortable.options.revert = false;
2403 sortable._trigger( "out", event, sortable._uiHash( sortable ) );
2404 sortable._mouseStop( event, true );
2406 // restore sortable behaviors that were modfied
2407 // when the draggable entered the sortable area (#9481)
2408 sortable.options.revert = sortable.options._revert;
2409 sortable.options.helper = sortable.options._helper;
2411 if ( sortable.placeholder ) {
2412 sortable.placeholder.remove();
2415 // Recalculate the draggable's offset considering the sortable
2416 // may have modified them in unexpected ways (#8809)
2417 draggable._refreshOffsets( event );
2418 ui.position = draggable._generatePosition( event, true );
2420 draggable._trigger( "fromSortable", event );
2422 // Inform draggable that the helper is no longer in a valid drop zone
2423 draggable.dropped = false;
2425 // Need to refreshPositions of all sortables just in case removing
2426 // from one sortable changes the location of other sortables (#9675)
2427 $.each( draggable.sortables, function() {
2428 this.refreshPositions();
2436 $.ui.plugin.add("draggable", "cursor", {
2437 start: function( event, ui, instance ) {
2438 var t = $( "body" ),
2439 o = instance.options;
2441 if (t.css("cursor")) {
2442 o._cursor = t.css("cursor");
2444 t.css("cursor", o.cursor);
2446 stop: function( event, ui, instance ) {
2447 var o = instance.options;
2449 $("body").css("cursor", o._cursor);
2454 $.ui.plugin.add("draggable", "opacity", {
2455 start: function( event, ui, instance ) {
2456 var t = $( ui.helper ),
2457 o = instance.options;
2458 if (t.css("opacity")) {
2459 o._opacity = t.css("opacity");
2461 t.css("opacity", o.opacity);
2463 stop: function( event, ui, instance ) {
2464 var o = instance.options;
2466 $(ui.helper).css("opacity", o._opacity);
2471 $.ui.plugin.add("draggable", "scroll", {
2472 start: function( event, ui, i ) {
2473 if ( !i.scrollParentNotHidden ) {
2474 i.scrollParentNotHidden = i.helper.scrollParent( false );
2477 if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] && i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) {
2478 i.overflowOffset = i.scrollParentNotHidden.offset();
2481 drag: function( event, ui, i ) {
2485 scrollParent = i.scrollParentNotHidden[ 0 ],
2486 document = i.document[ 0 ];
2488 if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) {
2489 if ( !o.axis || o.axis !== "x" ) {
2490 if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY < o.scrollSensitivity ) {
2491 scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed;
2492 } else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) {
2493 scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed;
2497 if ( !o.axis || o.axis !== "y" ) {
2498 if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX < o.scrollSensitivity ) {
2499 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed;
2500 } else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) {
2501 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed;
2507 if (!o.axis || o.axis !== "x") {
2508 if (event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
2509 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
2510 } else if ($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
2511 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
2515 if (!o.axis || o.axis !== "y") {
2516 if (event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
2517 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
2518 } else if ($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
2519 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
2525 if (scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
2526 $.ui.ddmanager.prepareOffsets(i, event);
2532 $.ui.plugin.add("draggable", "snap", {
2533 start: function( event, ui, i ) {
2537 i.snapElements = [];
2539 $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() {
2542 if (this !== i.element[0]) {
2543 i.snapElements.push({
2545 width: $t.outerWidth(), height: $t.outerHeight(),
2546 top: $o.top, left: $o.left
2552 drag: function( event, ui, inst ) {
2554 var ts, bs, ls, rs, l, r, t, b, i, first,
2556 d = o.snapTolerance,
2557 x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
2558 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
2560 for (i = inst.snapElements.length - 1; i >= 0; i--){
2562 l = inst.snapElements[i].left - inst.margins.left;
2563 r = l + inst.snapElements[i].width;
2564 t = inst.snapElements[i].top - inst.margins.top;
2565 b = t + inst.snapElements[i].height;
2567 if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || !$.contains( inst.snapElements[ i ].item.ownerDocument, inst.snapElements[ i ].item ) ) {
2568 if (inst.snapElements[i].snapping) {
2569 (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
2571 inst.snapElements[i].snapping = false;
2575 if (o.snapMode !== "inner") {
2576 ts = Math.abs(t - y2) <= d;
2577 bs = Math.abs(b - y1) <= d;
2578 ls = Math.abs(l - x2) <= d;
2579 rs = Math.abs(r - x1) <= d;
2581 ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top;
2584 ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top;
2587 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left;
2590 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left;
2594 first = (ts || bs || ls || rs);
2596 if (o.snapMode !== "outer") {
2597 ts = Math.abs(t - y1) <= d;
2598 bs = Math.abs(b - y2) <= d;
2599 ls = Math.abs(l - x1) <= d;
2600 rs = Math.abs(r - x2) <= d;
2602 ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top;
2605 ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top;
2608 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left;
2611 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left;
2615 if (!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) {
2616 (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
2618 inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
2625 $.ui.plugin.add("draggable", "stack", {
2626 start: function( event, ui, instance ) {
2628 o = instance.options,
2629 group = $.makeArray($(o.stack)).sort(function(a, b) {
2630 return (parseInt($(a).css("zIndex"), 10) || 0) - (parseInt($(b).css("zIndex"), 10) || 0);
2633 if (!group.length) { return; }
2635 min = parseInt($(group[0]).css("zIndex"), 10) || 0;
2636 $(group).each(function(i) {
2637 $(this).css("zIndex", min + i);
2639 this.css("zIndex", (min + group.length));
2643 $.ui.plugin.add("draggable", "zIndex", {
2644 start: function( event, ui, instance ) {
2645 var t = $( ui.helper ),
2646 o = instance.options;
2648 if (t.css("zIndex")) {
2649 o._zIndex = t.css("zIndex");
2651 t.css("zIndex", o.zIndex);
2653 stop: function( event, ui, instance ) {
2654 var o = instance.options;
2657 $(ui.helper).css("zIndex", o._zIndex);
2662 var draggable = $.ui.draggable;
2666 * jQuery UI Droppable 1.11.3
2667 * http://jqueryui.com
2669 * Copyright jQuery Foundation and other contributors
2670 * Released under the MIT license.
2671 * http://jquery.org/license
2673 * http://api.jqueryui.com/droppable/
2677 $.widget( "ui.droppable", {
2679 widgetEventPrefix: "drop",
2687 tolerance: "intersect",
2696 _create: function() {
2702 this.isover = false;
2705 this.accept = $.isFunction( accept ) ? accept : function( d ) {
2706 return d.is( accept );
2709 this.proportions = function( /* valueToWrite */ ) {
2710 if ( arguments.length ) {
2711 // Store the droppable's proportions
2712 proportions = arguments[ 0 ];
2714 // Retrieve or derive the droppable's proportions
2715 return proportions ?
2718 width: this.element[ 0 ].offsetWidth,
2719 height: this.element[ 0 ].offsetHeight
2724 this._addToManager( o.scope );
2726 o.addClasses && this.element.addClass( "ui-droppable" );
2730 _addToManager: function( scope ) {
2731 // Add the reference and positions to the manager
2732 $.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || [];
2733 $.ui.ddmanager.droppables[ scope ].push( this );
2736 _splice: function( drop ) {
2738 for ( ; i < drop.length; i++ ) {
2739 if ( drop[ i ] === this ) {
2740 drop.splice( i, 1 );
2745 _destroy: function() {
2746 var drop = $.ui.ddmanager.droppables[ this.options.scope ];
2748 this._splice( drop );
2750 this.element.removeClass( "ui-droppable ui-droppable-disabled" );
2753 _setOption: function( key, value ) {
2755 if ( key === "accept" ) {
2756 this.accept = $.isFunction( value ) ? value : function( d ) {
2757 return d.is( value );
2759 } else if ( key === "scope" ) {
2760 var drop = $.ui.ddmanager.droppables[ this.options.scope ];
2762 this._splice( drop );
2763 this._addToManager( value );
2766 this._super( key, value );
2769 _activate: function( event ) {
2770 var draggable = $.ui.ddmanager.current;
2771 if ( this.options.activeClass ) {
2772 this.element.addClass( this.options.activeClass );
2775 this._trigger( "activate", event, this.ui( draggable ) );
2779 _deactivate: function( event ) {
2780 var draggable = $.ui.ddmanager.current;
2781 if ( this.options.activeClass ) {
2782 this.element.removeClass( this.options.activeClass );
2785 this._trigger( "deactivate", event, this.ui( draggable ) );
2789 _over: function( event ) {
2791 var draggable = $.ui.ddmanager.current;
2793 // Bail if draggable and droppable are same element
2794 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
2798 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
2799 if ( this.options.hoverClass ) {
2800 this.element.addClass( this.options.hoverClass );
2802 this._trigger( "over", event, this.ui( draggable ) );
2807 _out: function( event ) {
2809 var draggable = $.ui.ddmanager.current;
2811 // Bail if draggable and droppable are same element
2812 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
2816 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
2817 if ( this.options.hoverClass ) {
2818 this.element.removeClass( this.options.hoverClass );
2820 this._trigger( "out", event, this.ui( draggable ) );
2825 _drop: function( event, custom ) {
2827 var draggable = custom || $.ui.ddmanager.current,
2828 childrenIntersection = false;
2830 // Bail if draggable and droppable are same element
2831 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
2835 this.element.find( ":data(ui-droppable)" ).not( ".ui-draggable-dragging" ).each(function() {
2836 var inst = $( this ).droppable( "instance" );
2838 inst.options.greedy &&
2839 !inst.options.disabled &&
2840 inst.options.scope === draggable.options.scope &&
2841 inst.accept.call( inst.element[ 0 ], ( draggable.currentItem || draggable.element ) ) &&
2842 $.ui.intersect( draggable, $.extend( inst, { offset: inst.element.offset() } ), inst.options.tolerance, event )
2843 ) { childrenIntersection = true; return false; }
2845 if ( childrenIntersection ) {
2849 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
2850 if ( this.options.activeClass ) {
2851 this.element.removeClass( this.options.activeClass );
2853 if ( this.options.hoverClass ) {
2854 this.element.removeClass( this.options.hoverClass );
2856 this._trigger( "drop", event, this.ui( draggable ) );
2857 return this.element;
2866 draggable: ( c.currentItem || c.element ),
2868 position: c.position,
2869 offset: c.positionAbs
2875 $.ui.intersect = (function() {
2876 function isOverAxis( x, reference, size ) {
2877 return ( x >= reference ) && ( x < ( reference + size ) );
2880 return function( draggable, droppable, toleranceMode, event ) {
2882 if ( !droppable.offset ) {
2886 var x1 = ( draggable.positionAbs || draggable.position.absolute ).left + draggable.margins.left,
2887 y1 = ( draggable.positionAbs || draggable.position.absolute ).top + draggable.margins.top,
2888 x2 = x1 + draggable.helperProportions.width,
2889 y2 = y1 + draggable.helperProportions.height,
2890 l = droppable.offset.left,
2891 t = droppable.offset.top,
2892 r = l + droppable.proportions().width,
2893 b = t + droppable.proportions().height;
2895 switch ( toleranceMode ) {
2897 return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b );
2899 return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half
2900 x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half
2901 t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half
2902 y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half
2904 return isOverAxis( event.pageY, t, droppable.proportions().height ) && isOverAxis( event.pageX, l, droppable.proportions().width );
2907 ( y1 >= t && y1 <= b ) || // Top edge touching
2908 ( y2 >= t && y2 <= b ) || // Bottom edge touching
2909 ( y1 < t && y2 > b ) // Surrounded vertically
2911 ( x1 >= l && x1 <= r ) || // Left edge touching
2912 ( x2 >= l && x2 <= r ) || // Right edge touching
2913 ( x1 < l && x2 > r ) // Surrounded horizontally
2922 This manager tracks offsets of draggables and droppables
2926 droppables: { "default": [] },
2927 prepareOffsets: function( t, event ) {
2930 m = $.ui.ddmanager.droppables[ t.options.scope ] || [],
2931 type = event ? event.type : null, // workaround for #2317
2932 list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack();
2934 droppablesLoop: for ( i = 0; i < m.length; i++ ) {
2936 // No disabled and non-accepted
2937 if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ], ( t.currentItem || t.element ) ) ) ) {
2941 // Filter out elements in the current dragged item
2942 for ( j = 0; j < list.length; j++ ) {
2943 if ( list[ j ] === m[ i ].element[ 0 ] ) {
2944 m[ i ].proportions().height = 0;
2945 continue droppablesLoop;
2949 m[ i ].visible = m[ i ].element.css( "display" ) !== "none";
2950 if ( !m[ i ].visible ) {
2954 // Activate the droppable if used directly from draggables
2955 if ( type === "mousedown" ) {
2956 m[ i ]._activate.call( m[ i ], event );
2959 m[ i ].offset = m[ i ].element.offset();
2960 m[ i ].proportions({ width: m[ i ].element[ 0 ].offsetWidth, height: m[ i ].element[ 0 ].offsetHeight });
2965 drop: function( draggable, event ) {
2967 var dropped = false;
2968 // Create a copy of the droppables in case the list changes during the drop (#9116)
2969 $.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() {
2971 if ( !this.options ) {
2974 if ( !this.options.disabled && this.visible && $.ui.intersect( draggable, this, this.options.tolerance, event ) ) {
2975 dropped = this._drop.call( this, event ) || dropped;
2978 if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
2980 this.isover = false;
2981 this._deactivate.call( this, event );
2988 dragStart: function( draggable, event ) {
2989 // Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003)
2990 draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() {
2991 if ( !draggable.options.refreshPositions ) {
2992 $.ui.ddmanager.prepareOffsets( draggable, event );
2996 drag: function( draggable, event ) {
2998 // If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
2999 if ( draggable.options.refreshPositions ) {
3000 $.ui.ddmanager.prepareOffsets( draggable, event );
3003 // Run through all droppables and check their positions based on specific tolerance options
3004 $.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() {
3006 if ( this.options.disabled || this.greedyChild || !this.visible ) {
3010 var parentInstance, scope, parent,
3011 intersects = $.ui.intersect( draggable, this, this.options.tolerance, event ),
3012 c = !intersects && this.isover ? "isout" : ( intersects && !this.isover ? "isover" : null );
3017 if ( this.options.greedy ) {
3018 // find droppable parents with same scope
3019 scope = this.options.scope;
3020 parent = this.element.parents( ":data(ui-droppable)" ).filter(function() {
3021 return $( this ).droppable( "instance" ).options.scope === scope;
3024 if ( parent.length ) {
3025 parentInstance = $( parent[ 0 ] ).droppable( "instance" );
3026 parentInstance.greedyChild = ( c === "isover" );
3030 // we just moved into a greedy child
3031 if ( parentInstance && c === "isover" ) {
3032 parentInstance.isover = false;
3033 parentInstance.isout = true;
3034 parentInstance._out.call( parentInstance, event );
3038 this[c === "isout" ? "isover" : "isout"] = false;
3039 this[c === "isover" ? "_over" : "_out"].call( this, event );
3041 // we just moved out of a greedy child
3042 if ( parentInstance && c === "isout" ) {
3043 parentInstance.isout = false;
3044 parentInstance.isover = true;
3045 parentInstance._over.call( parentInstance, event );
3050 dragStop: function( draggable, event ) {
3051 draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" );
3052 // Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003)
3053 if ( !draggable.options.refreshPositions ) {
3054 $.ui.ddmanager.prepareOffsets( draggable, event );
3059 var droppable = $.ui.droppable;
3063 * jQuery UI Resizable 1.11.3
3064 * http://jqueryui.com
3066 * Copyright jQuery Foundation and other contributors
3067 * Released under the MIT license.
3068 * http://jquery.org/license
3070 * http://api.jqueryui.com/resizable/
3074 $.widget("ui.resizable", $.ui.mouse, {
3076 widgetEventPrefix: "resize",
3080 animateDuration: "slow",
3081 animateEasing: "swing",
3102 _num: function( value ) {
3103 return parseInt( value, 10 ) || 0;
3106 _isNumber: function( value ) {
3107 return !isNaN( parseInt( value, 10 ) );
3110 _hasScroll: function( el, a ) {
3112 if ( $( el ).css( "overflow" ) === "hidden") {
3116 var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
3119 if ( el[ scroll ] > 0 ) {
3123 // TODO: determine which cases actually cause this to happen
3124 // if the element doesn't have the scroll set, see if it's possible to
3127 has = ( el[ scroll ] > 0 );
3132 _create: function() {
3134 var n, i, handle, axis, hname,
3137 this.element.addClass("ui-resizable");
3140 _aspectRatio: !!(o.aspectRatio),
3141 aspectRatio: o.aspectRatio,
3142 originalElement: this.element,
3143 _proportionallyResizeElements: [],
3144 _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
3147 // Wrap the element if it cannot hold child nodes
3148 if (this.element[0].nodeName.match(/^(canvas|textarea|input|select|button|img)$/i)) {
3151 $("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({
3152 position: this.element.css("position"),
3153 width: this.element.outerWidth(),
3154 height: this.element.outerHeight(),
3155 top: this.element.css("top"),
3156 left: this.element.css("left")
3160 this.element = this.element.parent().data(
3161 "ui-resizable", this.element.resizable( "instance" )
3164 this.elementIsWrapper = true;
3167 marginLeft: this.originalElement.css("marginLeft"),
3168 marginTop: this.originalElement.css("marginTop"),
3169 marginRight: this.originalElement.css("marginRight"),
3170 marginBottom: this.originalElement.css("marginBottom")
3172 this.originalElement.css({
3179 // Prevent Safari textarea resize
3180 this.originalResizeStyle = this.originalElement.css("resize");
3181 this.originalElement.css("resize", "none");
3183 this._proportionallyResizeElements.push( this.originalElement.css({
3190 // avoid IE jump (hard set the margin)
3191 this.originalElement.css({ margin: this.originalElement.css("margin") });
3193 this._proportionallyResize();
3196 this.handles = o.handles ||
3197 ( !$(".ui-resizable-handle", this.element).length ?
3199 n: ".ui-resizable-n",
3200 e: ".ui-resizable-e",
3201 s: ".ui-resizable-s",
3202 w: ".ui-resizable-w",
3203 se: ".ui-resizable-se",
3204 sw: ".ui-resizable-sw",
3205 ne: ".ui-resizable-ne",
3206 nw: ".ui-resizable-nw"
3209 if (this.handles.constructor === String) {
3211 if ( this.handles === "all") {
3212 this.handles = "n,e,s,w,se,sw,ne,nw";
3215 n = this.handles.split(",");
3218 for (i = 0; i < n.length; i++) {
3220 handle = $.trim(n[i]);
3221 hname = "ui-resizable-" + handle;
3222 axis = $("<div class='ui-resizable-handle " + hname + "'></div>");
3224 axis.css({ zIndex: o.zIndex });
3226 // TODO : What's going on here?
3227 if ("se" === handle) {
3228 axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se");
3231 this.handles[handle] = ".ui-resizable-" + handle;
3232 this.element.append(axis);
3237 this._renderAxis = function(target) {
3239 var i, axis, padPos, padWrapper;
3241 target = target || this.element;
3243 for (i in this.handles) {
3245 if (this.handles[i].constructor === String) {
3246 this.handles[i] = this.element.children( this.handles[ i ] ).first().show();
3249 if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)) {
3251 axis = $(this.handles[i], this.element);
3253 padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
3255 padPos = [ "padding",
3256 /ne|nw|n/.test(i) ? "Top" :
3257 /se|sw|s/.test(i) ? "Bottom" :
3258 /^e$/.test(i) ? "Right" : "Left" ].join("");
3260 target.css(padPos, padWrapper);
3262 this._proportionallyResize();
3266 // TODO: What's that good for? There's not anything to be executed left
3267 if (!$(this.handles[i]).length) {
3273 // TODO: make renderAxis a prototype function
3274 this._renderAxis(this.element);
3276 this._handles = $(".ui-resizable-handle", this.element)
3277 .disableSelection();
3279 this._handles.mouseover(function() {
3280 if (!that.resizing) {
3281 if (this.className) {
3282 axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
3284 that.axis = axis && axis[1] ? axis[1] : "se";
3289 this._handles.hide();
3291 .addClass("ui-resizable-autohide")
3292 .mouseenter(function() {
3296 $(this).removeClass("ui-resizable-autohide");
3297 that._handles.show();
3299 .mouseleave(function() {
3303 if (!that.resizing) {
3304 $(this).addClass("ui-resizable-autohide");
3305 that._handles.hide();
3314 _destroy: function() {
3316 this._mouseDestroy();
3319 _destroy = function(exp) {
3321 .removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing")
3322 .removeData("resizable")
3323 .removeData("ui-resizable")
3324 .unbind(".resizable")
3325 .find(".ui-resizable-handle")
3329 // TODO: Unwrap at same DOM position
3330 if (this.elementIsWrapper) {
3331 _destroy(this.element);
3332 wrapper = this.element;
3333 this.originalElement.css({
3334 position: wrapper.css("position"),
3335 width: wrapper.outerWidth(),
3336 height: wrapper.outerHeight(),
3337 top: wrapper.css("top"),
3338 left: wrapper.css("left")
3339 }).insertAfter( wrapper );
3343 this.originalElement.css("resize", this.originalResizeStyle);
3344 _destroy(this.originalElement);
3349 _mouseCapture: function(event) {
3353 for (i in this.handles) {
3354 handle = $(this.handles[i])[0];
3355 if (handle === event.target || $.contains(handle, event.target)) {
3360 return !this.options.disabled && capture;
3363 _mouseStart: function(event) {
3365 var curleft, curtop, cursor,
3369 this.resizing = true;
3371 this._renderProxy();
3373 curleft = this._num(this.helper.css("left"));
3374 curtop = this._num(this.helper.css("top"));
3376 if (o.containment) {
3377 curleft += $(o.containment).scrollLeft() || 0;
3378 curtop += $(o.containment).scrollTop() || 0;
3381 this.offset = this.helper.offset();
3382 this.position = { left: curleft, top: curtop };
3384 this.size = this._helper ? {
3385 width: this.helper.width(),
3386 height: this.helper.height()
3392 this.originalSize = this._helper ? {
3393 width: el.outerWidth(),
3394 height: el.outerHeight()
3401 width: el.outerWidth() - el.width(),
3402 height: el.outerHeight() - el.height()
3405 this.originalPosition = { left: curleft, top: curtop };
3406 this.originalMousePosition = { left: event.pageX, top: event.pageY };
3408 this.aspectRatio = (typeof o.aspectRatio === "number") ?
3410 ((this.originalSize.width / this.originalSize.height) || 1);
3412 cursor = $(".ui-resizable-" + this.axis).css("cursor");
3413 $("body").css("cursor", cursor === "auto" ? this.axis + "-resize" : cursor);
3415 el.addClass("ui-resizable-resizing");
3416 this._propagate("start", event);
3420 _mouseDrag: function(event) {
3423 smp = this.originalMousePosition,
3425 dx = (event.pageX - smp.left) || 0,
3426 dy = (event.pageY - smp.top) || 0,
3427 trigger = this._change[a];
3429 this._updatePrevProperties();
3435 data = trigger.apply(this, [ event, dx, dy ]);
3437 this._updateVirtualBoundaries(event.shiftKey);
3438 if (this._aspectRatio || event.shiftKey) {
3439 data = this._updateRatio(data, event);
3442 data = this._respectSize(data, event);
3444 this._updateCache(data);
3446 this._propagate("resize", event);
3448 props = this._applyChanges();
3450 if ( !this._helper && this._proportionallyResizeElements.length ) {
3451 this._proportionallyResize();
3454 if ( !$.isEmptyObject( props ) ) {
3455 this._updatePrevProperties();
3456 this._trigger( "resize", event, this.ui() );
3457 this._applyChanges();
3463 _mouseStop: function(event) {
3465 this.resizing = false;
3466 var pr, ista, soffseth, soffsetw, s, left, top,
3467 o = this.options, that = this;
3471 pr = this._proportionallyResizeElements;
3472 ista = pr.length && (/textarea/i).test(pr[0].nodeName);
3473 soffseth = ista && this._hasScroll(pr[0], "left") ? 0 : that.sizeDiff.height;
3474 soffsetw = ista ? 0 : that.sizeDiff.width;
3477 width: (that.helper.width() - soffsetw),
3478 height: (that.helper.height() - soffseth)
3480 left = (parseInt(that.element.css("left"), 10) +
3481 (that.position.left - that.originalPosition.left)) || null;
3482 top = (parseInt(that.element.css("top"), 10) +
3483 (that.position.top - that.originalPosition.top)) || null;
3486 this.element.css($.extend(s, { top: top, left: left }));
3489 that.helper.height(that.size.height);
3490 that.helper.width(that.size.width);
3492 if (this._helper && !o.animate) {
3493 this._proportionallyResize();
3497 $("body").css("cursor", "auto");
3499 this.element.removeClass("ui-resizable-resizing");
3501 this._propagate("stop", event);
3504 this.helper.remove();
3511 _updatePrevProperties: function() {
3512 this.prevPosition = {
3513 top: this.position.top,
3514 left: this.position.left
3517 width: this.size.width,
3518 height: this.size.height
3522 _applyChanges: function() {
3525 if ( this.position.top !== this.prevPosition.top ) {
3526 props.top = this.position.top + "px";
3528 if ( this.position.left !== this.prevPosition.left ) {
3529 props.left = this.position.left + "px";
3531 if ( this.size.width !== this.prevSize.width ) {
3532 props.width = this.size.width + "px";
3534 if ( this.size.height !== this.prevSize.height ) {
3535 props.height = this.size.height + "px";
3538 this.helper.css( props );
3543 _updateVirtualBoundaries: function(forceAspectRatio) {
3544 var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
3548 minWidth: this._isNumber(o.minWidth) ? o.minWidth : 0,
3549 maxWidth: this._isNumber(o.maxWidth) ? o.maxWidth : Infinity,
3550 minHeight: this._isNumber(o.minHeight) ? o.minHeight : 0,
3551 maxHeight: this._isNumber(o.maxHeight) ? o.maxHeight : Infinity
3554 if (this._aspectRatio || forceAspectRatio) {
3555 pMinWidth = b.minHeight * this.aspectRatio;
3556 pMinHeight = b.minWidth / this.aspectRatio;
3557 pMaxWidth = b.maxHeight * this.aspectRatio;
3558 pMaxHeight = b.maxWidth / this.aspectRatio;
3560 if (pMinWidth > b.minWidth) {
3561 b.minWidth = pMinWidth;
3563 if (pMinHeight > b.minHeight) {
3564 b.minHeight = pMinHeight;
3566 if (pMaxWidth < b.maxWidth) {
3567 b.maxWidth = pMaxWidth;
3569 if (pMaxHeight < b.maxHeight) {
3570 b.maxHeight = pMaxHeight;
3573 this._vBoundaries = b;
3576 _updateCache: function(data) {
3577 this.offset = this.helper.offset();
3578 if (this._isNumber(data.left)) {
3579 this.position.left = data.left;
3581 if (this._isNumber(data.top)) {
3582 this.position.top = data.top;
3584 if (this._isNumber(data.height)) {
3585 this.size.height = data.height;
3587 if (this._isNumber(data.width)) {
3588 this.size.width = data.width;
3592 _updateRatio: function( data ) {
3594 var cpos = this.position,
3598 if (this._isNumber(data.height)) {
3599 data.width = (data.height * this.aspectRatio);
3600 } else if (this._isNumber(data.width)) {
3601 data.height = (data.width / this.aspectRatio);
3605 data.left = cpos.left + (csize.width - data.width);
3609 data.top = cpos.top + (csize.height - data.height);
3610 data.left = cpos.left + (csize.width - data.width);
3616 _respectSize: function( data ) {
3618 var o = this._vBoundaries,
3620 ismaxw = this._isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width),
3621 ismaxh = this._isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height),
3622 isminw = this._isNumber(data.width) && o.minWidth && (o.minWidth > data.width),
3623 isminh = this._isNumber(data.height) && o.minHeight && (o.minHeight > data.height),
3624 dw = this.originalPosition.left + this.originalSize.width,
3625 dh = this.position.top + this.size.height,
3626 cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
3628 data.width = o.minWidth;
3631 data.height = o.minHeight;
3634 data.width = o.maxWidth;
3637 data.height = o.maxHeight;
3641 data.left = dw - o.minWidth;
3644 data.left = dw - o.maxWidth;
3647 data.top = dh - o.minHeight;
3650 data.top = dh - o.maxHeight;
3653 // Fixing jump error on top/left - bug #2330
3654 if (!data.width && !data.height && !data.left && data.top) {
3656 } else if (!data.width && !data.height && !data.top && data.left) {
3663 _getPaddingPlusBorderDimensions: function( element ) {
3667 element.css( "borderTopWidth" ),
3668 element.css( "borderRightWidth" ),
3669 element.css( "borderBottomWidth" ),
3670 element.css( "borderLeftWidth" )
3673 element.css( "paddingTop" ),
3674 element.css( "paddingRight" ),
3675 element.css( "paddingBottom" ),
3676 element.css( "paddingLeft" )
3679 for ( ; i < 4; i++ ) {
3680 widths[ i ] = ( parseInt( borders[ i ], 10 ) || 0 );
3681 widths[ i ] += ( parseInt( paddings[ i ], 10 ) || 0 );
3685 height: widths[ 0 ] + widths[ 2 ],
3686 width: widths[ 1 ] + widths[ 3 ]
3690 _proportionallyResize: function() {
3692 if (!this._proportionallyResizeElements.length) {
3698 element = this.helper || this.element;
3700 for ( ; i < this._proportionallyResizeElements.length; i++) {
3702 prel = this._proportionallyResizeElements[i];
3704 // TODO: Seems like a bug to cache this.outerDimensions
3705 // considering that we are in a loop.
3706 if (!this.outerDimensions) {
3707 this.outerDimensions = this._getPaddingPlusBorderDimensions( prel );
3711 height: (element.height() - this.outerDimensions.height) || 0,
3712 width: (element.width() - this.outerDimensions.width) || 0
3719 _renderProxy: function() {
3721 var el = this.element, o = this.options;
3722 this.elementOffset = el.offset();
3726 this.helper = this.helper || $("<div style='overflow:hidden;'></div>");
3728 this.helper.addClass(this._helper).css({
3729 width: this.element.outerWidth() - 1,
3730 height: this.element.outerHeight() - 1,
3731 position: "absolute",
3732 left: this.elementOffset.left + "px",
3733 top: this.elementOffset.top + "px",
3734 zIndex: ++o.zIndex //TODO: Don't modify option
3739 .disableSelection();
3742 this.helper = this.element;
3748 e: function(event, dx) {
3749 return { width: this.originalSize.width + dx };
3751 w: function(event, dx) {
3752 var cs = this.originalSize, sp = this.originalPosition;
3753 return { left: sp.left + dx, width: cs.width - dx };
3755 n: function(event, dx, dy) {
3756 var cs = this.originalSize, sp = this.originalPosition;
3757 return { top: sp.top + dy, height: cs.height - dy };
3759 s: function(event, dx, dy) {
3760 return { height: this.originalSize.height + dy };
3762 se: function(event, dx, dy) {
3763 return $.extend(this._change.s.apply(this, arguments),
3764 this._change.e.apply(this, [ event, dx, dy ]));
3766 sw: function(event, dx, dy) {
3767 return $.extend(this._change.s.apply(this, arguments),
3768 this._change.w.apply(this, [ event, dx, dy ]));
3770 ne: function(event, dx, dy) {
3771 return $.extend(this._change.n.apply(this, arguments),
3772 this._change.e.apply(this, [ event, dx, dy ]));
3774 nw: function(event, dx, dy) {
3775 return $.extend(this._change.n.apply(this, arguments),
3776 this._change.w.apply(this, [ event, dx, dy ]));
3780 _propagate: function(n, event) {
3781 $.ui.plugin.call(this, n, [ event, this.ui() ]);
3782 (n !== "resize" && this._trigger(n, event, this.ui()));
3789 originalElement: this.originalElement,
3790 element: this.element,
3791 helper: this.helper,
3792 position: this.position,
3794 originalSize: this.originalSize,
3795 originalPosition: this.originalPosition
3802 * Resizable Extensions
3805 $.ui.plugin.add("resizable", "animate", {
3807 stop: function( event ) {
3808 var that = $(this).resizable( "instance" ),
3810 pr = that._proportionallyResizeElements,
3811 ista = pr.length && (/textarea/i).test(pr[0].nodeName),
3812 soffseth = ista && that._hasScroll(pr[0], "left") ? 0 : that.sizeDiff.height,
3813 soffsetw = ista ? 0 : that.sizeDiff.width,
3814 style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) },
3815 left = (parseInt(that.element.css("left"), 10) +
3816 (that.position.left - that.originalPosition.left)) || null,
3817 top = (parseInt(that.element.css("top"), 10) +
3818 (that.position.top - that.originalPosition.top)) || null;
3820 that.element.animate(
3821 $.extend(style, top && left ? { top: top, left: left } : {}), {
3822 duration: o.animateDuration,
3823 easing: o.animateEasing,
3827 width: parseInt(that.element.css("width"), 10),
3828 height: parseInt(that.element.css("height"), 10),
3829 top: parseInt(that.element.css("top"), 10),
3830 left: parseInt(that.element.css("left"), 10)
3833 if (pr && pr.length) {
3834 $(pr[0]).css({ width: data.width, height: data.height });
3837 // propagating resize, and updating values for each animation step
3838 that._updateCache(data);
3839 that._propagate("resize", event);
3848 $.ui.plugin.add( "resizable", "containment", {
3851 var element, p, co, ch, cw, width, height,
3852 that = $( this ).resizable( "instance" ),
3856 ce = ( oc instanceof $ ) ? oc.get( 0 ) : ( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc;
3862 that.containerElement = $( ce );
3864 if ( /document/.test( oc ) || oc === document ) {
3865 that.containerOffset = {
3869 that.containerPosition = {
3875 element: $( document ),
3878 width: $( document ).width(),
3879 height: $( document ).height() || document.body.parentNode.scrollHeight
3884 $([ "Top", "Right", "Left", "Bottom" ]).each(function( i, name ) {
3885 p[ i ] = that._num( element.css( "padding" + name ) );
3888 that.containerOffset = element.offset();
3889 that.containerPosition = element.position();
3890 that.containerSize = {
3891 height: ( element.innerHeight() - p[ 3 ] ),
3892 width: ( element.innerWidth() - p[ 1 ] )
3895 co = that.containerOffset;
3896 ch = that.containerSize.height;
3897 cw = that.containerSize.width;
3898 width = ( that._hasScroll ( ce, "left" ) ? ce.scrollWidth : cw );
3899 height = ( that._hasScroll ( ce ) ? ce.scrollHeight : ch ) ;
3911 resize: function( event ) {
3912 var woset, hoset, isParent, isOffsetRelative,
3913 that = $( this ).resizable( "instance" ),
3915 co = that.containerOffset,
3917 pRatio = that._aspectRatio || event.shiftKey,
3922 ce = that.containerElement,
3923 continueResize = true;
3925 if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) {
3929 if ( cp.left < ( that._helper ? co.left : 0 ) ) {
3930 that.size.width = that.size.width +
3932 ( that.position.left - co.left ) :
3933 ( that.position.left - cop.left ) );
3936 that.size.height = that.size.width / that.aspectRatio;
3937 continueResize = false;
3939 that.position.left = o.helper ? co.left : 0;
3942 if ( cp.top < ( that._helper ? co.top : 0 ) ) {
3943 that.size.height = that.size.height +
3945 ( that.position.top - co.top ) :
3946 that.position.top );
3949 that.size.width = that.size.height * that.aspectRatio;
3950 continueResize = false;
3952 that.position.top = that._helper ? co.top : 0;
3955 isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 );
3956 isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) );
3958 if ( isParent && isOffsetRelative ) {
3959 that.offset.left = that.parentData.left + that.position.left;
3960 that.offset.top = that.parentData.top + that.position.top;
3962 that.offset.left = that.element.offset().left;
3963 that.offset.top = that.element.offset().top;
3966 woset = Math.abs( that.sizeDiff.width +
3968 that.offset.left - cop.left :
3969 (that.offset.left - co.left)) );
3971 hoset = Math.abs( that.sizeDiff.height +
3973 that.offset.top - cop.top :
3974 (that.offset.top - co.top)) );
3976 if ( woset + that.size.width >= that.parentData.width ) {
3977 that.size.width = that.parentData.width - woset;
3979 that.size.height = that.size.width / that.aspectRatio;
3980 continueResize = false;
3984 if ( hoset + that.size.height >= that.parentData.height ) {
3985 that.size.height = that.parentData.height - hoset;
3987 that.size.width = that.size.height * that.aspectRatio;
3988 continueResize = false;
3992 if ( !continueResize ) {
3993 that.position.left = that.prevPosition.left;
3994 that.position.top = that.prevPosition.top;
3995 that.size.width = that.prevSize.width;
3996 that.size.height = that.prevSize.height;
4001 var that = $( this ).resizable( "instance" ),
4003 co = that.containerOffset,
4004 cop = that.containerPosition,
4005 ce = that.containerElement,
4006 helper = $( that.helper ),
4007 ho = helper.offset(),
4008 w = helper.outerWidth() - that.sizeDiff.width,
4009 h = helper.outerHeight() - that.sizeDiff.height;
4011 if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) {
4013 left: ho.left - cop.left - co.left,
4019 if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) {
4021 left: ho.left - cop.left - co.left,
4029 $.ui.plugin.add("resizable", "alsoResize", {
4032 var that = $(this).resizable( "instance" ),
4034 _store = function(exp) {
4035 $(exp).each(function() {
4037 el.data("ui-resizable-alsoresize", {
4038 width: parseInt(el.width(), 10), height: parseInt(el.height(), 10),
4039 left: parseInt(el.css("left"), 10), top: parseInt(el.css("top"), 10)
4044 if (typeof(o.alsoResize) === "object" && !o.alsoResize.parentNode) {
4045 if (o.alsoResize.length) {
4046 o.alsoResize = o.alsoResize[0];
4047 _store(o.alsoResize);
4049 $.each(o.alsoResize, function(exp) {
4054 _store(o.alsoResize);
4058 resize: function(event, ui) {
4059 var that = $(this).resizable( "instance" ),
4061 os = that.originalSize,
4062 op = that.originalPosition,
4064 height: (that.size.height - os.height) || 0,
4065 width: (that.size.width - os.width) || 0,
4066 top: (that.position.top - op.top) || 0,
4067 left: (that.position.left - op.left) || 0
4070 _alsoResize = function(exp, c) {
4071 $(exp).each(function() {
4072 var el = $(this), start = $(this).data("ui-resizable-alsoresize"), style = {},
4073 css = c && c.length ?
4075 el.parents(ui.originalElement[0]).length ?
4076 [ "width", "height" ] :
4077 [ "width", "height", "top", "left" ];
4079 $.each(css, function(i, prop) {
4080 var sum = (start[prop] || 0) + (delta[prop] || 0);
4081 if (sum && sum >= 0) {
4082 style[prop] = sum || null;
4090 if (typeof(o.alsoResize) === "object" && !o.alsoResize.nodeType) {
4091 $.each(o.alsoResize, function(exp, c) {
4092 _alsoResize(exp, c);
4095 _alsoResize(o.alsoResize);
4100 $(this).removeData("resizable-alsoresize");
4104 $.ui.plugin.add("resizable", "ghost", {
4108 var that = $(this).resizable( "instance" ), o = that.options, cs = that.size;
4110 that.ghost = that.originalElement.clone();
4115 position: "relative",
4122 .addClass("ui-resizable-ghost")
4123 .addClass(typeof o.ghost === "string" ? o.ghost : "");
4125 that.ghost.appendTo(that.helper);
4129 resize: function() {
4130 var that = $(this).resizable( "instance" );
4133 position: "relative",
4134 height: that.size.height,
4135 width: that.size.width
4141 var that = $(this).resizable( "instance" );
4142 if (that.ghost && that.helper) {
4143 that.helper.get(0).removeChild(that.ghost.get(0));
4149 $.ui.plugin.add("resizable", "grid", {
4151 resize: function() {
4152 var outerDimensions,
4153 that = $(this).resizable( "instance" ),
4156 os = that.originalSize,
4157 op = that.originalPosition,
4159 grid = typeof o.grid === "number" ? [ o.grid, o.grid ] : o.grid,
4160 gridX = (grid[0] || 1),
4161 gridY = (grid[1] || 1),
4162 ox = Math.round((cs.width - os.width) / gridX) * gridX,
4163 oy = Math.round((cs.height - os.height) / gridY) * gridY,
4164 newWidth = os.width + ox,
4165 newHeight = os.height + oy,
4166 isMaxWidth = o.maxWidth && (o.maxWidth < newWidth),
4167 isMaxHeight = o.maxHeight && (o.maxHeight < newHeight),
4168 isMinWidth = o.minWidth && (o.minWidth > newWidth),
4169 isMinHeight = o.minHeight && (o.minHeight > newHeight);
4186 if (/^(se|s|e)$/.test(a)) {
4187 that.size.width = newWidth;
4188 that.size.height = newHeight;
4189 } else if (/^(ne)$/.test(a)) {
4190 that.size.width = newWidth;
4191 that.size.height = newHeight;
4192 that.position.top = op.top - oy;
4193 } else if (/^(sw)$/.test(a)) {
4194 that.size.width = newWidth;
4195 that.size.height = newHeight;
4196 that.position.left = op.left - ox;
4198 if ( newHeight - gridY <= 0 || newWidth - gridX <= 0) {
4199 outerDimensions = that._getPaddingPlusBorderDimensions( this );
4202 if ( newHeight - gridY > 0 ) {
4203 that.size.height = newHeight;
4204 that.position.top = op.top - oy;
4206 newHeight = gridY - outerDimensions.height;
4207 that.size.height = newHeight;
4208 that.position.top = op.top + os.height - newHeight;
4210 if ( newWidth - gridX > 0 ) {
4211 that.size.width = newWidth;
4212 that.position.left = op.left - ox;
4214 newWidth = gridX - outerDimensions.width;
4215 that.size.width = newWidth;
4216 that.position.left = op.left + os.width - newWidth;
4223 var resizable = $.ui.resizable;
4227 * jQuery UI Selectable 1.11.3
4228 * http://jqueryui.com
4230 * Copyright jQuery Foundation and other contributors
4231 * Released under the MIT license.
4232 * http://jquery.org/license
4234 * http://api.jqueryui.com/selectable/
4238 var selectable = $.widget("ui.selectable", $.ui.mouse, {
4255 _create: function() {
4259 this.element.addClass("ui-selectable");
4261 this.dragged = false;
4263 // cache selectee children based on filter
4264 this.refresh = function() {
4265 selectees = $(that.options.filter, that.element[0]);
4266 selectees.addClass("ui-selectee");
4267 selectees.each(function() {
4268 var $this = $(this),
4269 pos = $this.offset();
4270 $.data(this, "selectable-item", {
4275 right: pos.left + $this.outerWidth(),
4276 bottom: pos.top + $this.outerHeight(),
4277 startselected: false,
4278 selected: $this.hasClass("ui-selected"),
4279 selecting: $this.hasClass("ui-selecting"),
4280 unselecting: $this.hasClass("ui-unselecting")
4286 this.selectees = selectees.addClass("ui-selectee");
4290 this.helper = $("<div class='ui-selectable-helper'></div>");
4293 _destroy: function() {
4295 .removeClass("ui-selectee")
4296 .removeData("selectable-item");
4298 .removeClass("ui-selectable ui-selectable-disabled");
4299 this._mouseDestroy();
4302 _mouseStart: function(event) {
4304 options = this.options;
4306 this.opos = [ event.pageX, event.pageY ];
4308 if (this.options.disabled) {
4312 this.selectees = $(options.filter, this.element[0]);
4314 this._trigger("start", event);
4316 $(options.appendTo).append(this.helper);
4317 // position helper (lasso)
4319 "left": event.pageX,
4325 if (options.autoRefresh) {
4329 this.selectees.filter(".ui-selected").each(function() {
4330 var selectee = $.data(this, "selectable-item");
4331 selectee.startselected = true;
4332 if (!event.metaKey && !event.ctrlKey) {
4333 selectee.$element.removeClass("ui-selected");
4334 selectee.selected = false;
4335 selectee.$element.addClass("ui-unselecting");
4336 selectee.unselecting = true;
4337 // selectable UNSELECTING callback
4338 that._trigger("unselecting", event, {
4339 unselecting: selectee.element
4344 $(event.target).parents().addBack().each(function() {
4346 selectee = $.data(this, "selectable-item");
4348 doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass("ui-selected");
4350 .removeClass(doSelect ? "ui-unselecting" : "ui-selected")
4351 .addClass(doSelect ? "ui-selecting" : "ui-unselecting");
4352 selectee.unselecting = !doSelect;
4353 selectee.selecting = doSelect;
4354 selectee.selected = doSelect;
4355 // selectable (UN)SELECTING callback
4357 that._trigger("selecting", event, {
4358 selecting: selectee.element
4361 that._trigger("unselecting", event, {
4362 unselecting: selectee.element
4371 _mouseDrag: function(event) {
4373 this.dragged = true;
4375 if (this.options.disabled) {
4381 options = this.options,
4387 if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; }
4388 if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; }
4389 this.helper.css({ left: x1, top: y1, width: x2 - x1, height: y2 - y1 });
4391 this.selectees.each(function() {
4392 var selectee = $.data(this, "selectable-item"),
4395 //prevent helper from being selected if appendTo: selectable
4396 if (!selectee || selectee.element === that.element[0]) {
4400 if (options.tolerance === "touch") {
4401 hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) );
4402 } else if (options.tolerance === "fit") {
4403 hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2);
4408 if (selectee.selected) {
4409 selectee.$element.removeClass("ui-selected");
4410 selectee.selected = false;
4412 if (selectee.unselecting) {
4413 selectee.$element.removeClass("ui-unselecting");
4414 selectee.unselecting = false;
4416 if (!selectee.selecting) {
4417 selectee.$element.addClass("ui-selecting");
4418 selectee.selecting = true;
4419 // selectable SELECTING callback
4420 that._trigger("selecting", event, {
4421 selecting: selectee.element
4426 if (selectee.selecting) {
4427 if ((event.metaKey || event.ctrlKey) && selectee.startselected) {
4428 selectee.$element.removeClass("ui-selecting");
4429 selectee.selecting = false;
4430 selectee.$element.addClass("ui-selected");
4431 selectee.selected = true;
4433 selectee.$element.removeClass("ui-selecting");
4434 selectee.selecting = false;
4435 if (selectee.startselected) {
4436 selectee.$element.addClass("ui-unselecting");
4437 selectee.unselecting = true;
4439 // selectable UNSELECTING callback
4440 that._trigger("unselecting", event, {
4441 unselecting: selectee.element
4445 if (selectee.selected) {
4446 if (!event.metaKey && !event.ctrlKey && !selectee.startselected) {
4447 selectee.$element.removeClass("ui-selected");
4448 selectee.selected = false;
4450 selectee.$element.addClass("ui-unselecting");
4451 selectee.unselecting = true;
4452 // selectable UNSELECTING callback
4453 that._trigger("unselecting", event, {
4454 unselecting: selectee.element
4464 _mouseStop: function(event) {
4467 this.dragged = false;
4469 $(".ui-unselecting", this.element[0]).each(function() {
4470 var selectee = $.data(this, "selectable-item");
4471 selectee.$element.removeClass("ui-unselecting");
4472 selectee.unselecting = false;
4473 selectee.startselected = false;
4474 that._trigger("unselected", event, {
4475 unselected: selectee.element
4478 $(".ui-selecting", this.element[0]).each(function() {
4479 var selectee = $.data(this, "selectable-item");
4480 selectee.$element.removeClass("ui-selecting").addClass("ui-selected");
4481 selectee.selecting = false;
4482 selectee.selected = true;
4483 selectee.startselected = true;
4484 that._trigger("selected", event, {
4485 selected: selectee.element
4488 this._trigger("stop", event);
4490 this.helper.remove();
4499 * jQuery UI Sortable 1.11.3
4500 * http://jqueryui.com
4502 * Copyright jQuery Foundation and other contributors
4503 * Released under the MIT license.
4504 * http://jquery.org/license
4506 * http://api.jqueryui.com/sortable/
4510 var sortable = $.widget("ui.sortable", $.ui.mouse, {
4512 widgetEventPrefix: "sort",
4522 forcePlaceholderSize: false,
4523 forceHelperSize: false,
4532 scrollSensitivity: 20,
4535 tolerance: "intersect",
4553 _isOverAxis: function( x, reference, size ) {
4554 return ( x >= reference ) && ( x < ( reference + size ) );
4557 _isFloating: function( item ) {
4558 return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display"));
4561 _create: function() {
4563 var o = this.options;
4564 this.containerCache = {};
4565 this.element.addClass("ui-sortable");
4570 //Let's determine if the items are being displayed horizontally
4571 this.floating = this.items.length ? o.axis === "x" || this._isFloating(this.items[0].item) : false;
4573 //Let's determine the parent's offset
4574 this.offset = this.element.offset();
4576 //Initialize mouse events for interaction
4579 this._setHandleClassName();
4586 _setOption: function( key, value ) {
4587 this._super( key, value );
4589 if ( key === "handle" ) {
4590 this._setHandleClassName();
4594 _setHandleClassName: function() {
4595 this.element.find( ".ui-sortable-handle" ).removeClass( "ui-sortable-handle" );
4596 $.each( this.items, function() {
4597 ( this.instance.options.handle ?
4598 this.item.find( this.instance.options.handle ) : this.item )
4599 .addClass( "ui-sortable-handle" );
4603 _destroy: function() {
4605 .removeClass( "ui-sortable ui-sortable-disabled" )
4606 .find( ".ui-sortable-handle" )
4607 .removeClass( "ui-sortable-handle" );
4608 this._mouseDestroy();
4610 for ( var i = this.items.length - 1; i >= 0; i-- ) {
4611 this.items[i].item.removeData(this.widgetName + "-item");
4617 _mouseCapture: function(event, overrideHandle) {
4618 var currentItem = null,
4619 validHandle = false,
4622 if (this.reverting) {
4626 if(this.options.disabled || this.options.type === "static") {
4630 //We have to refresh the items data once first
4631 this._refreshItems(event);
4633 //Find out if the clicked node (or one of its parents) is a actual item in this.items
4634 $(event.target).parents().each(function() {
4635 if($.data(this, that.widgetName + "-item") === that) {
4636 currentItem = $(this);
4640 if($.data(event.target, that.widgetName + "-item") === that) {
4641 currentItem = $(event.target);
4647 if(this.options.handle && !overrideHandle) {
4648 $(this.options.handle, currentItem).find("*").addBack().each(function() {
4649 if(this === event.target) {
4658 this.currentItem = currentItem;
4659 this._removeCurrentsFromItems();
4664 _mouseStart: function(event, overrideHandle, noActivation) {
4669 this.currentContainer = this;
4671 //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
4672 this.refreshPositions();
4674 //Create and append the visible helper
4675 this.helper = this._createHelper(event);
4677 //Cache the helper size
4678 this._cacheHelperProportions();
4681 * - Position generation -
4682 * This block generates everything position related - it's the core of draggables.
4685 //Cache the margins of the original element
4686 this._cacheMargins();
4688 //Get the next scrolling parent
4689 this.scrollParent = this.helper.scrollParent();
4691 //The element's absolute position on the page minus margins
4692 this.offset = this.currentItem.offset();
4694 top: this.offset.top - this.margins.top,
4695 left: this.offset.left - this.margins.left
4698 $.extend(this.offset, {
4699 click: { //Where the click happened, relative to the element
4700 left: event.pageX - this.offset.left,
4701 top: event.pageY - this.offset.top
4703 parent: this._getParentOffset(),
4704 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
4707 // Only after we got the offset, we can change the helper's position to absolute
4708 // TODO: Still need to figure out a way to make relative sorting possible
4709 this.helper.css("position", "absolute");
4710 this.cssPosition = this.helper.css("position");
4712 //Generate the original position
4713 this.originalPosition = this._generatePosition(event);
4714 this.originalPageX = event.pageX;
4715 this.originalPageY = event.pageY;
4717 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
4718 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
4720 //Cache the former DOM position
4721 this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };
4723 //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
4724 if(this.helper[0] !== this.currentItem[0]) {
4725 this.currentItem.hide();
4728 //Create the placeholder
4729 this._createPlaceholder();
4731 //Set a containment if given in the options
4733 this._setContainment();
4736 if( o.cursor && o.cursor !== "auto" ) { // cursor option
4737 body = this.document.find( "body" );
4740 this.storedCursor = body.css( "cursor" );
4741 body.css( "cursor", o.cursor );
4743 this.storedStylesheet = $( "<style>*{ cursor: "+o.cursor+" !important; }</style>" ).appendTo( body );
4746 if(o.opacity) { // opacity option
4747 if (this.helper.css("opacity")) {
4748 this._storedOpacity = this.helper.css("opacity");
4750 this.helper.css("opacity", o.opacity);
4753 if(o.zIndex) { // zIndex option
4754 if (this.helper.css("zIndex")) {
4755 this._storedZIndex = this.helper.css("zIndex");
4757 this.helper.css("zIndex", o.zIndex);
4761 if(this.scrollParent[0] !== this.document[0] && this.scrollParent[0].tagName !== "HTML") {
4762 this.overflowOffset = this.scrollParent.offset();
4766 this._trigger("start", event, this._uiHash());
4768 //Recache the helper size
4769 if(!this._preserveHelperProportions) {
4770 this._cacheHelperProportions();
4774 //Post "activate" events to possible containers
4775 if( !noActivation ) {
4776 for ( i = this.containers.length - 1; i >= 0; i-- ) {
4777 this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
4781 //Prepare possible droppables
4782 if($.ui.ddmanager) {
4783 $.ui.ddmanager.current = this;
4786 if ($.ui.ddmanager && !o.dropBehaviour) {
4787 $.ui.ddmanager.prepareOffsets(this, event);
4790 this.dragging = true;
4792 this.helper.addClass("ui-sortable-helper");
4793 this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
4798 _mouseDrag: function(event) {
4799 var i, item, itemElement, intersection,
4803 //Compute the helpers position
4804 this.position = this._generatePosition(event);
4805 this.positionAbs = this._convertPositionTo("absolute");
4807 if (!this.lastPositionAbs) {
4808 this.lastPositionAbs = this.positionAbs;
4812 if(this.options.scroll) {
4813 if(this.scrollParent[0] !== this.document[0] && this.scrollParent[0].tagName !== "HTML") {
4815 if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
4816 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
4817 } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) {
4818 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
4821 if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
4822 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
4823 } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) {
4824 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
4829 if(event.pageY - this.document.scrollTop() < o.scrollSensitivity) {
4830 scrolled = this.document.scrollTop(this.document.scrollTop() - o.scrollSpeed);
4831 } else if(this.window.height() - (event.pageY - this.document.scrollTop()) < o.scrollSensitivity) {
4832 scrolled = this.document.scrollTop(this.document.scrollTop() + o.scrollSpeed);
4835 if(event.pageX - this.document.scrollLeft() < o.scrollSensitivity) {
4836 scrolled = this.document.scrollLeft(this.document.scrollLeft() - o.scrollSpeed);
4837 } else if(this.window.width() - (event.pageX - this.document.scrollLeft()) < o.scrollSensitivity) {
4838 scrolled = this.document.scrollLeft(this.document.scrollLeft() + o.scrollSpeed);
4843 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
4844 $.ui.ddmanager.prepareOffsets(this, event);
4848 //Regenerate the absolute position used for position checks
4849 this.positionAbs = this._convertPositionTo("absolute");
4851 //Set the helper position
4852 if(!this.options.axis || this.options.axis !== "y") {
4853 this.helper[0].style.left = this.position.left+"px";
4855 if(!this.options.axis || this.options.axis !== "x") {
4856 this.helper[0].style.top = this.position.top+"px";
4860 for (i = this.items.length - 1; i >= 0; i--) {
4862 //Cache variables and intersection, continue if no intersection
4863 item = this.items[i];
4864 itemElement = item.item[0];
4865 intersection = this._intersectsWithPointer(item);
4866 if (!intersection) {
4870 // Only put the placeholder inside the current Container, skip all
4871 // items from other containers. This works because when moving
4872 // an item from one container to another the
4873 // currentContainer is switched before the placeholder is moved.
4875 // Without this, moving items in "sub-sortables" can cause
4876 // the placeholder to jitter between the outer and inner container.
4877 if (item.instance !== this.currentContainer) {
4881 // cannot intersect with itself
4882 // no useless actions that have been done before
4883 // no action if the item moved is the parent of the item checked
4884 if (itemElement !== this.currentItem[0] &&
4885 this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement &&
4886 !$.contains(this.placeholder[0], itemElement) &&
4887 (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true)
4890 this.direction = intersection === 1 ? "down" : "up";
4892 if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) {
4893 this._rearrange(event, item);
4898 this._trigger("change", event, this._uiHash());
4903 //Post events to containers
4904 this._contactContainers(event);
4906 //Interconnect with droppables
4907 if($.ui.ddmanager) {
4908 $.ui.ddmanager.drag(this, event);
4912 this._trigger("sort", event, this._uiHash());
4914 this.lastPositionAbs = this.positionAbs;
4919 _mouseStop: function(event, noPropagation) {
4925 //If we are using droppables, inform the manager about the drop
4926 if ($.ui.ddmanager && !this.options.dropBehaviour) {
4927 $.ui.ddmanager.drop(this, event);
4930 if(this.options.revert) {
4932 cur = this.placeholder.offset(),
4933 axis = this.options.axis,
4936 if ( !axis || axis === "x" ) {
4937 animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === this.document[0].body ? 0 : this.offsetParent[0].scrollLeft);
4939 if ( !axis || axis === "y" ) {
4940 animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === this.document[0].body ? 0 : this.offsetParent[0].scrollTop);
4942 this.reverting = true;
4943 $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() {
4947 this._clear(event, noPropagation);
4954 cancel: function() {
4958 this._mouseUp({ target: null });
4960 if(this.options.helper === "original") {
4961 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
4963 this.currentItem.show();
4966 //Post deactivating events to containers
4967 for (var i = this.containers.length - 1; i >= 0; i--){
4968 this.containers[i]._trigger("deactivate", null, this._uiHash(this));
4969 if(this.containers[i].containerCache.over) {
4970 this.containers[i]._trigger("out", null, this._uiHash(this));
4971 this.containers[i].containerCache.over = 0;
4977 if (this.placeholder) {
4978 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
4979 if(this.placeholder[0].parentNode) {
4980 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
4982 if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) {
4983 this.helper.remove();
4993 if(this.domPosition.prev) {
4994 $(this.domPosition.prev).after(this.currentItem);
4996 $(this.domPosition.parent).prepend(this.currentItem);
5004 serialize: function(o) {
5006 var items = this._getItemsAsjQuery(o && o.connected),
5010 $(items).each(function() {
5011 var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/));
5013 str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2]));
5017 if(!str.length && o.key) {
5018 str.push(o.key + "=");
5021 return str.join("&");
5025 toArray: function(o) {
5027 var items = this._getItemsAsjQuery(o && o.connected),
5032 items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); });
5037 /* Be careful with the following core functions */
5038 _intersectsWith: function(item) {
5040 var x1 = this.positionAbs.left,
5041 x2 = x1 + this.helperProportions.width,
5042 y1 = this.positionAbs.top,
5043 y2 = y1 + this.helperProportions.height,
5047 b = t + item.height,
5048 dyClick = this.offset.click.top,
5049 dxClick = this.offset.click.left,
5050 isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ),
5051 isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ),
5052 isOverElement = isOverElementHeight && isOverElementWidth;
5054 if ( this.options.tolerance === "pointer" ||
5055 this.options.forcePointerForContainers ||
5056 (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"])
5058 return isOverElement;
5061 return (l < x1 + (this.helperProportions.width / 2) && // Right Half
5062 x2 - (this.helperProportions.width / 2) < r && // Left Half
5063 t < y1 + (this.helperProportions.height / 2) && // Bottom Half
5064 y2 - (this.helperProportions.height / 2) < b ); // Top Half
5069 _intersectsWithPointer: function(item) {
5071 var isOverElementHeight = (this.options.axis === "x") || this._isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
5072 isOverElementWidth = (this.options.axis === "y") || this._isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
5073 isOverElement = isOverElementHeight && isOverElementWidth,
5074 verticalDirection = this._getDragVerticalDirection(),
5075 horizontalDirection = this._getDragHorizontalDirection();
5077 if (!isOverElement) {
5081 return this.floating ?
5082 ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 )
5083 : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) );
5087 _intersectsWithSides: function(item) {
5089 var isOverBottomHalf = this._isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
5090 isOverRightHalf = this._isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
5091 verticalDirection = this._getDragVerticalDirection(),
5092 horizontalDirection = this._getDragHorizontalDirection();
5094 if (this.floating && horizontalDirection) {
5095 return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf));
5097 return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf));
5102 _getDragVerticalDirection: function() {
5103 var delta = this.positionAbs.top - this.lastPositionAbs.top;
5104 return delta !== 0 && (delta > 0 ? "down" : "up");
5107 _getDragHorizontalDirection: function() {
5108 var delta = this.positionAbs.left - this.lastPositionAbs.left;
5109 return delta !== 0 && (delta > 0 ? "right" : "left");
5112 refresh: function(event) {
5113 this._refreshItems(event);
5114 this._setHandleClassName();
5115 this.refreshPositions();
5119 _connectWith: function() {
5120 var options = this.options;
5121 return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith;
5124 _getItemsAsjQuery: function(connected) {
5126 var i, j, cur, inst,
5129 connectWith = this._connectWith();
5131 if(connectWith && connected) {
5132 for (i = connectWith.length - 1; i >= 0; i--){
5133 cur = $(connectWith[i], this.document[0]);
5134 for ( j = cur.length - 1; j >= 0; j--){
5135 inst = $.data(cur[j], this.widgetFullName);
5136 if(inst && inst !== this && !inst.options.disabled) {
5137 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]);
5143 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]);
5145 function addItems() {
5148 for (i = queries.length - 1; i >= 0; i--){
5149 queries[i][0].each( addItems );
5156 _removeCurrentsFromItems: function() {
5158 var list = this.currentItem.find(":data(" + this.widgetName + "-item)");
5160 this.items = $.grep(this.items, function (item) {
5161 for (var j=0; j < list.length; j++) {
5162 if(list[j] === item.item[0]) {
5171 _refreshItems: function(event) {
5174 this.containers = [this];
5176 var i, j, cur, inst, targetData, _queries, item, queriesLength,
5178 queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]],
5179 connectWith = this._connectWith();
5181 if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down
5182 for (i = connectWith.length - 1; i >= 0; i--){
5183 cur = $(connectWith[i], this.document[0]);
5184 for (j = cur.length - 1; j >= 0; j--){
5185 inst = $.data(cur[j], this.widgetFullName);
5186 if(inst && inst !== this && !inst.options.disabled) {
5187 queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
5188 this.containers.push(inst);
5194 for (i = queries.length - 1; i >= 0; i--) {
5195 targetData = queries[i][1];
5196 _queries = queries[i][0];
5198 for (j=0, queriesLength = _queries.length; j < queriesLength; j++) {
5199 item = $(_queries[j]);
5201 item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager)
5205 instance: targetData,
5206 width: 0, height: 0,
5214 refreshPositions: function(fast) {
5216 //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
5217 if(this.offsetParent && this.helper) {
5218 this.offset.parent = this._getParentOffset();
5223 for (i = this.items.length - 1; i >= 0; i--){
5224 item = this.items[i];
5226 //We ignore calculating positions of all connected containers when we're not over them
5227 if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) {
5231 t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
5234 item.width = t.outerWidth();
5235 item.height = t.outerHeight();
5243 if(this.options.custom && this.options.custom.refreshContainers) {
5244 this.options.custom.refreshContainers.call(this);
5246 for (i = this.containers.length - 1; i >= 0; i--){
5247 p = this.containers[i].element.offset();
5248 this.containers[i].containerCache.left = p.left;
5249 this.containers[i].containerCache.top = p.top;
5250 this.containers[i].containerCache.width = this.containers[i].element.outerWidth();
5251 this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
5258 _createPlaceholder: function(that) {
5259 that = that || this;
5263 if(!o.placeholder || o.placeholder.constructor === String) {
5264 className = o.placeholder;
5266 element: function() {
5268 var nodeName = that.currentItem[0].nodeName.toLowerCase(),
5269 element = $( "<" + nodeName + ">", that.document[0] )
5270 .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder")
5271 .removeClass("ui-sortable-helper");
5273 if ( nodeName === "tr" ) {
5274 that.currentItem.children().each(function() {
5275 $( "<td> </td>", that.document[0] )
5276 .attr( "colspan", $( this ).attr( "colspan" ) || 1 )
5277 .appendTo( element );
5279 } else if ( nodeName === "img" ) {
5280 element.attr( "src", that.currentItem.attr( "src" ) );
5284 element.css( "visibility", "hidden" );
5289 update: function(container, p) {
5291 // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that
5292 // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified
5293 if(className && !o.forcePlaceholderSize) {
5297 //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
5298 if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); }
5299 if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); }
5304 //Create the placeholder
5305 that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem));
5307 //Append it after the actual current item
5308 that.currentItem.after(that.placeholder);
5310 //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
5311 o.placeholder.update(that, that.placeholder);
5315 _contactContainers: function(event) {
5316 var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom, floating, axis,
5317 innermostContainer = null,
5318 innermostIndex = null;
5320 // get innermost container that intersects with item
5321 for (i = this.containers.length - 1; i >= 0; i--) {
5323 // never consider a container that's located within the item itself
5324 if($.contains(this.currentItem[0], this.containers[i].element[0])) {
5328 if(this._intersectsWith(this.containers[i].containerCache)) {
5330 // if we've already found a container and it's more "inner" than this, then continue
5331 if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) {
5335 innermostContainer = this.containers[i];
5339 // container doesn't intersect. trigger "out" event if necessary
5340 if(this.containers[i].containerCache.over) {
5341 this.containers[i]._trigger("out", event, this._uiHash(this));
5342 this.containers[i].containerCache.over = 0;
5348 // if no intersecting containers found, return
5349 if(!innermostContainer) {
5353 // move the item into the container if it's not there already
5354 if(this.containers.length === 1) {
5355 if (!this.containers[innermostIndex].containerCache.over) {
5356 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
5357 this.containers[innermostIndex].containerCache.over = 1;
5361 //When entering a new container, we will find the item with the least distance and append our item near it
5363 itemWithLeastDistance = null;
5364 floating = innermostContainer.floating || this._isFloating(this.currentItem);
5365 posProperty = floating ? "left" : "top";
5366 sizeProperty = floating ? "width" : "height";
5367 axis = floating ? "clientX" : "clientY";
5369 for (j = this.items.length - 1; j >= 0; j--) {
5370 if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) {
5373 if(this.items[j].item[0] === this.currentItem[0]) {
5377 cur = this.items[j].item.offset()[posProperty];
5379 if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) {
5383 if ( Math.abs( event[ axis ] - cur ) < dist ) {
5384 dist = Math.abs( event[ axis ] - cur );
5385 itemWithLeastDistance = this.items[ j ];
5386 this.direction = nearBottom ? "up": "down";
5390 //Check if dropOnEmpty is enabled
5391 if(!itemWithLeastDistance && !this.options.dropOnEmpty) {
5395 if(this.currentContainer === this.containers[innermostIndex]) {
5396 if ( !this.currentContainer.containerCache.over ) {
5397 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() );
5398 this.currentContainer.containerCache.over = 1;
5403 itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true);
5404 this._trigger("change", event, this._uiHash());
5405 this.containers[innermostIndex]._trigger("change", event, this._uiHash(this));
5406 this.currentContainer = this.containers[innermostIndex];
5408 //Update the placeholder
5409 this.options.placeholder.update(this.currentContainer, this.placeholder);
5411 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
5412 this.containers[innermostIndex].containerCache.over = 1;
5418 _createHelper: function(event) {
5420 var o = this.options,
5421 helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem);
5423 //Add the helper to the DOM if that didn't happen already
5424 if(!helper.parents("body").length) {
5425 $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
5428 if(helper[0] === this.currentItem[0]) {
5429 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") };
5432 if(!helper[0].style.width || o.forceHelperSize) {
5433 helper.width(this.currentItem.width());
5435 if(!helper[0].style.height || o.forceHelperSize) {
5436 helper.height(this.currentItem.height());
5443 _adjustOffsetFromHelper: function(obj) {
5444 if (typeof obj === "string") {
5445 obj = obj.split(" ");
5447 if ($.isArray(obj)) {
5448 obj = {left: +obj[0], top: +obj[1] || 0};
5450 if ("left" in obj) {
5451 this.offset.click.left = obj.left + this.margins.left;
5453 if ("right" in obj) {
5454 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
5457 this.offset.click.top = obj.top + this.margins.top;
5459 if ("bottom" in obj) {
5460 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
5464 _getParentOffset: function() {
5467 //Get the offsetParent and cache its position
5468 this.offsetParent = this.helper.offsetParent();
5469 var po = this.offsetParent.offset();
5471 // This is a special case where we need to modify a offset calculated on start, since the following happened:
5472 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
5473 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
5474 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
5475 if(this.cssPosition === "absolute" && this.scrollParent[0] !== this.document[0] && $.contains(this.scrollParent[0], this.offsetParent[0])) {
5476 po.left += this.scrollParent.scrollLeft();
5477 po.top += this.scrollParent.scrollTop();
5480 // This needs to be actually done for all browsers, since pageX/pageY includes this information
5481 // with an ugly IE fix
5482 if( this.offsetParent[0] === this.document[0].body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
5483 po = { top: 0, left: 0 };
5487 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
5488 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
5493 _getRelativeOffset: function() {
5495 if(this.cssPosition === "relative") {
5496 var p = this.currentItem.position();
5498 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
5499 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
5502 return { top: 0, left: 0 };
5507 _cacheMargins: function() {
5509 left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
5510 top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
5514 _cacheHelperProportions: function() {
5515 this.helperProportions = {
5516 width: this.helper.outerWidth(),
5517 height: this.helper.outerHeight()
5521 _setContainment: function() {
5525 if(o.containment === "parent") {
5526 o.containment = this.helper[0].parentNode;
5528 if(o.containment === "document" || o.containment === "window") {
5529 this.containment = [
5530 0 - this.offset.relative.left - this.offset.parent.left,
5531 0 - this.offset.relative.top - this.offset.parent.top,
5532 o.containment === "document" ? this.document.width() : this.window.width() - this.helperProportions.width - this.margins.left,
5533 (o.containment === "document" ? this.document.width() : this.window.height() || this.document[0].body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
5537 if(!(/^(document|window|parent)$/).test(o.containment)) {
5538 ce = $(o.containment)[0];
5539 co = $(o.containment).offset();
5540 over = ($(ce).css("overflow") !== "hidden");
5542 this.containment = [
5543 co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
5544 co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
5545 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,
5546 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
5552 _convertPositionTo: function(d, pos) {
5555 pos = this.position;
5557 var mod = d === "absolute" ? 1 : -1,
5558 scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== this.document[0] && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent,
5559 scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
5563 pos.top + // The absolute mouse position
5564 this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
5565 this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
5566 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
5569 pos.left + // The absolute mouse position
5570 this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
5571 this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
5572 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
5578 _generatePosition: function(event) {
5582 pageX = event.pageX,
5583 pageY = event.pageY,
5584 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);
5586 // This is another very weird special case that only happens for relative elements:
5587 // 1. If the css position is relative
5588 // 2. and the scroll parent is the document or similar to the offset parent
5589 // we have to refresh the relative offset during the scroll so there are no jumps
5590 if(this.cssPosition === "relative" && !(this.scrollParent[0] !== this.document[0] && this.scrollParent[0] !== this.offsetParent[0])) {
5591 this.offset.relative = this._getRelativeOffset();
5595 * - Position constraining -
5596 * Constrain the position to a mix of grid, containment.
5599 if(this.originalPosition) { //If we are not dragging yet, we won't check for options
5601 if(this.containment) {
5602 if(event.pageX - this.offset.click.left < this.containment[0]) {
5603 pageX = this.containment[0] + this.offset.click.left;
5605 if(event.pageY - this.offset.click.top < this.containment[1]) {
5606 pageY = this.containment[1] + this.offset.click.top;
5608 if(event.pageX - this.offset.click.left > this.containment[2]) {
5609 pageX = this.containment[2] + this.offset.click.left;
5611 if(event.pageY - this.offset.click.top > this.containment[3]) {
5612 pageY = this.containment[3] + this.offset.click.top;
5617 top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
5618 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;
5620 left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
5621 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;
5628 pageY - // The absolute mouse position
5629 this.offset.click.top - // Click offset (relative to the element)
5630 this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
5631 this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
5632 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
5635 pageX - // The absolute mouse position
5636 this.offset.click.left - // Click offset (relative to the element)
5637 this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
5638 this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
5639 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
5645 _rearrange: function(event, i, a, hardRefresh) {
5647 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));
5649 //Various things done here to improve the performance:
5650 // 1. we create a setTimeout, that calls refreshPositions
5651 // 2. on the instance, we have a counter variable, that get's higher after every append
5652 // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
5653 // 4. this lets only the last addition to the timeout stack through
5654 this.counter = this.counter ? ++this.counter : 1;
5655 var counter = this.counter;
5657 this._delay(function() {
5658 if(counter === this.counter) {
5659 this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
5665 _clear: function(event, noPropagation) {
5667 this.reverting = false;
5668 // We delay all events that have to be triggered to after the point where the placeholder has been removed and
5669 // everything else normalized again
5671 delayedTriggers = [];
5673 // We first have to update the dom position of the actual currentItem
5674 // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
5675 if(!this._noFinalSort && this.currentItem.parent().length) {
5676 this.placeholder.before(this.currentItem);
5678 this._noFinalSort = null;
5680 if(this.helper[0] === this.currentItem[0]) {
5681 for(i in this._storedCSS) {
5682 if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") {
5683 this._storedCSS[i] = "";
5686 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
5688 this.currentItem.show();
5691 if(this.fromOutside && !noPropagation) {
5692 delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
5694 if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) {
5695 delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed
5698 // Check if the items Container has Changed and trigger appropriate
5700 if (this !== this.currentContainer) {
5701 if(!noPropagation) {
5702 delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); });
5703 delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
5704 delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
5709 //Post events to containers
5710 function delayEvent( type, instance, container ) {
5711 return function( event ) {
5712 container._trigger( type, event, instance._uiHash( instance ) );
5715 for (i = this.containers.length - 1; i >= 0; i--){
5716 if (!noPropagation) {
5717 delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) );
5719 if(this.containers[i].containerCache.over) {
5720 delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) );
5721 this.containers[i].containerCache.over = 0;
5725 //Do what was originally in plugins
5726 if ( this.storedCursor ) {
5727 this.document.find( "body" ).css( "cursor", this.storedCursor );
5728 this.storedStylesheet.remove();
5730 if(this._storedOpacity) {
5731 this.helper.css("opacity", this._storedOpacity);
5733 if(this._storedZIndex) {
5734 this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex);
5737 this.dragging = false;
5739 if(!noPropagation) {
5740 this._trigger("beforeStop", event, this._uiHash());
5743 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
5744 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
5746 if ( !this.cancelHelperRemoval ) {
5747 if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
5748 this.helper.remove();
5753 if(!noPropagation) {
5754 for (i=0; i < delayedTriggers.length; i++) {
5755 delayedTriggers[i].call(this, event);
5756 } //Trigger all delayed events
5757 this._trigger("stop", event, this._uiHash());
5760 this.fromOutside = false;
5761 return !this.cancelHelperRemoval;
5765 _trigger: function() {
5766 if ($.Widget.prototype._trigger.apply(this, arguments) === false) {
5771 _uiHash: function(_inst) {
5772 var inst = _inst || this;
5774 helper: inst.helper,
5775 placeholder: inst.placeholder || $([]),
5776 position: inst.position,
5777 originalPosition: inst.originalPosition,
5778 offset: inst.positionAbs,
5779 item: inst.currentItem,
5780 sender: _inst ? _inst.element : null
5788 * jQuery UI Accordion 1.11.3
5789 * http://jqueryui.com
5791 * Copyright jQuery Foundation and other contributors
5792 * Released under the MIT license.
5793 * http://jquery.org/license
5795 * http://api.jqueryui.com/accordion/
5799 var accordion = $.widget( "ui.accordion", {
5806 header: "> li > :first-child,> :not(li):even",
5807 heightStyle: "auto",
5809 activeHeader: "ui-icon-triangle-1-s",
5810 header: "ui-icon-triangle-1-e"
5815 beforeActivate: null
5819 borderTopWidth: "hide",
5820 borderBottomWidth: "hide",
5822 paddingBottom: "hide",
5827 borderTopWidth: "show",
5828 borderBottomWidth: "show",
5830 paddingBottom: "show",
5834 _create: function() {
5835 var options = this.options;
5836 this.prevShow = this.prevHide = $();
5837 this.element.addClass( "ui-accordion ui-widget ui-helper-reset" )
5839 .attr( "role", "tablist" );
5841 // don't allow collapsible: false and active: false / null
5842 if ( !options.collapsible && (options.active === false || options.active == null) ) {
5846 this._processPanels();
5847 // handle negative values
5848 if ( options.active < 0 ) {
5849 options.active += this.headers.length;
5854 _getCreateEventData: function() {
5856 header: this.active,
5857 panel: !this.active.length ? $() : this.active.next()
5861 _createIcons: function() {
5862 var icons = this.options.icons;
5865 .addClass( "ui-accordion-header-icon ui-icon " + icons.header )
5866 .prependTo( this.headers );
5867 this.active.children( ".ui-accordion-header-icon" )
5868 .removeClass( icons.header )
5869 .addClass( icons.activeHeader );
5870 this.headers.addClass( "ui-accordion-icons" );
5874 _destroyIcons: function() {
5876 .removeClass( "ui-accordion-icons" )
5877 .children( ".ui-accordion-header-icon" )
5881 _destroy: function() {
5884 // clean up main element
5886 .removeClass( "ui-accordion ui-widget ui-helper-reset" )
5887 .removeAttr( "role" );
5891 .removeClass( "ui-accordion-header ui-accordion-header-active ui-state-default " +
5892 "ui-corner-all ui-state-active ui-state-disabled ui-corner-top" )
5893 .removeAttr( "role" )
5894 .removeAttr( "aria-expanded" )
5895 .removeAttr( "aria-selected" )
5896 .removeAttr( "aria-controls" )
5897 .removeAttr( "tabIndex" )
5900 this._destroyIcons();
5902 // clean up content panels
5903 contents = this.headers.next()
5904 .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom " +
5905 "ui-accordion-content ui-accordion-content-active ui-state-disabled" )
5906 .css( "display", "" )
5907 .removeAttr( "role" )
5908 .removeAttr( "aria-hidden" )
5909 .removeAttr( "aria-labelledby" )
5912 if ( this.options.heightStyle !== "content" ) {
5913 contents.css( "height", "" );
5917 _setOption: function( key, value ) {
5918 if ( key === "active" ) {
5919 // _activate() will handle invalid values and update this.options
5920 this._activate( value );
5924 if ( key === "event" ) {
5925 if ( this.options.event ) {
5926 this._off( this.headers, this.options.event );
5928 this._setupEvents( value );
5931 this._super( key, value );
5933 // setting collapsible: false while collapsed; open first panel
5934 if ( key === "collapsible" && !value && this.options.active === false ) {
5935 this._activate( 0 );
5938 if ( key === "icons" ) {
5939 this._destroyIcons();
5941 this._createIcons();
5945 // #5332 - opacity doesn't cascade to positioned elements in IE
5946 // so we need to add the disabled class to the headers and panels
5947 if ( key === "disabled" ) {
5949 .toggleClass( "ui-state-disabled", !!value )
5950 .attr( "aria-disabled", value );
5951 this.headers.add( this.headers.next() )
5952 .toggleClass( "ui-state-disabled", !!value );
5956 _keydown: function( event ) {
5957 if ( event.altKey || event.ctrlKey ) {
5961 var keyCode = $.ui.keyCode,
5962 length = this.headers.length,
5963 currentIndex = this.headers.index( event.target ),
5966 switch ( event.keyCode ) {
5969 toFocus = this.headers[ ( currentIndex + 1 ) % length ];
5973 toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
5977 this._eventHandler( event );
5980 toFocus = this.headers[ 0 ];
5983 toFocus = this.headers[ length - 1 ];
5988 $( event.target ).attr( "tabIndex", -1 );
5989 $( toFocus ).attr( "tabIndex", 0 );
5991 event.preventDefault();
5995 _panelKeyDown: function( event ) {
5996 if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
5997 $( event.currentTarget ).prev().focus();
6001 refresh: function() {
6002 var options = this.options;
6003 this._processPanels();
6005 // was collapsed or no panel
6006 if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) {
6007 options.active = false;
6009 // active false only when collapsible is true
6010 } else if ( options.active === false ) {
6011 this._activate( 0 );
6012 // was active, but active panel is gone
6013 } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
6014 // all remaining panel are disabled
6015 if ( this.headers.length === this.headers.find(".ui-state-disabled").length ) {
6016 options.active = false;
6018 // activate previous panel
6020 this._activate( Math.max( 0, options.active - 1 ) );
6022 // was active, active panel still exists
6024 // make sure active index is correct
6025 options.active = this.headers.index( this.active );
6028 this._destroyIcons();
6033 _processPanels: function() {
6034 var prevHeaders = this.headers,
6035 prevPanels = this.panels;
6037 this.headers = this.element.find( this.options.header )
6038 .addClass( "ui-accordion-header ui-state-default ui-corner-all" );
6040 this.panels = this.headers.next()
6041 .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" )
6042 .filter( ":not(.ui-accordion-content-active)" )
6045 // Avoid memory leaks (#10056)
6047 this._off( prevHeaders.not( this.headers ) );
6048 this._off( prevPanels.not( this.panels ) );
6052 _refresh: function() {
6054 options = this.options,
6055 heightStyle = options.heightStyle,
6056 parent = this.element.parent();
6058 this.active = this._findActive( options.active )
6059 .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" )
6060 .removeClass( "ui-corner-all" );
6062 .addClass( "ui-accordion-content-active" )
6066 .attr( "role", "tab" )
6068 var header = $( this ),
6069 headerId = header.uniqueId().attr( "id" ),
6070 panel = header.next(),
6071 panelId = panel.uniqueId().attr( "id" );
6072 header.attr( "aria-controls", panelId );
6073 panel.attr( "aria-labelledby", headerId );
6076 .attr( "role", "tabpanel" );
6081 "aria-selected": "false",
6082 "aria-expanded": "false",
6087 "aria-hidden": "true"
6091 // make sure at least one header is in the tab order
6092 if ( !this.active.length ) {
6093 this.headers.eq( 0 ).attr( "tabIndex", 0 );
6096 "aria-selected": "true",
6097 "aria-expanded": "true",
6102 "aria-hidden": "false"
6106 this._createIcons();
6108 this._setupEvents( options.event );
6110 if ( heightStyle === "fill" ) {
6111 maxHeight = parent.height();
6112 this.element.siblings( ":visible" ).each(function() {
6113 var elem = $( this ),
6114 position = elem.css( "position" );
6116 if ( position === "absolute" || position === "fixed" ) {
6119 maxHeight -= elem.outerHeight( true );
6122 this.headers.each(function() {
6123 maxHeight -= $( this ).outerHeight( true );
6128 $( this ).height( Math.max( 0, maxHeight -
6129 $( this ).innerHeight() + $( this ).height() ) );
6131 .css( "overflow", "auto" );
6132 } else if ( heightStyle === "auto" ) {
6136 maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
6138 .height( maxHeight );
6142 _activate: function( index ) {
6143 var active = this._findActive( index )[ 0 ];
6145 // trying to activate the already active panel
6146 if ( active === this.active[ 0 ] ) {
6150 // trying to collapse, simulate a click on the currently active header
6151 active = active || this.active[ 0 ];
6153 this._eventHandler({
6155 currentTarget: active,
6156 preventDefault: $.noop
6160 _findActive: function( selector ) {
6161 return typeof selector === "number" ? this.headers.eq( selector ) : $();
6164 _setupEvents: function( event ) {
6169 $.each( event.split( " " ), function( index, eventName ) {
6170 events[ eventName ] = "_eventHandler";
6174 this._off( this.headers.add( this.headers.next() ) );
6175 this._on( this.headers, events );
6176 this._on( this.headers.next(), { keydown: "_panelKeyDown" });
6177 this._hoverable( this.headers );
6178 this._focusable( this.headers );
6181 _eventHandler: function( event ) {
6182 var options = this.options,
6183 active = this.active,
6184 clicked = $( event.currentTarget ),
6185 clickedIsActive = clicked[ 0 ] === active[ 0 ],
6186 collapsing = clickedIsActive && options.collapsible,
6187 toShow = collapsing ? $() : clicked.next(),
6188 toHide = active.next(),
6192 newHeader: collapsing ? $() : clicked,
6196 event.preventDefault();
6199 // click on active header, but not collapsible
6200 ( clickedIsActive && !options.collapsible ) ||
6201 // allow canceling activation
6202 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
6206 options.active = collapsing ? false : this.headers.index( clicked );
6208 // when the call to ._toggle() comes after the class changes
6209 // it causes a very odd bug in IE 8 (see #6720)
6210 this.active = clickedIsActive ? $() : clicked;
6211 this._toggle( eventData );
6214 // corner classes on the previously active header stay after the animation
6215 active.removeClass( "ui-accordion-header-active ui-state-active" );
6216 if ( options.icons ) {
6217 active.children( ".ui-accordion-header-icon" )
6218 .removeClass( options.icons.activeHeader )
6219 .addClass( options.icons.header );
6222 if ( !clickedIsActive ) {
6224 .removeClass( "ui-corner-all" )
6225 .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" );
6226 if ( options.icons ) {
6227 clicked.children( ".ui-accordion-header-icon" )
6228 .removeClass( options.icons.header )
6229 .addClass( options.icons.activeHeader );
6234 .addClass( "ui-accordion-content-active" );
6238 _toggle: function( data ) {
6239 var toShow = data.newPanel,
6240 toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
6242 // handle activating a panel during the animation for another activation
6243 this.prevShow.add( this.prevHide ).stop( true, true );
6244 this.prevShow = toShow;
6245 this.prevHide = toHide;
6247 if ( this.options.animate ) {
6248 this._animate( toShow, toHide, data );
6252 this._toggleComplete( data );
6256 "aria-hidden": "true"
6258 toHide.prev().attr({
6259 "aria-selected": "false",
6260 "aria-expanded": "false"
6262 // if we're switching panels, remove the old header from the tab order
6263 // if we're opening from collapsed state, remove the previous header from the tab order
6264 // if we're collapsing, then keep the collapsing header in the tab order
6265 if ( toShow.length && toHide.length ) {
6266 toHide.prev().attr({
6268 "aria-expanded": "false"
6270 } else if ( toShow.length ) {
6271 this.headers.filter(function() {
6272 return parseInt( $( this ).attr( "tabIndex" ), 10 ) === 0;
6274 .attr( "tabIndex", -1 );
6278 .attr( "aria-hidden", "false" )
6281 "aria-selected": "true",
6282 "aria-expanded": "true",
6287 _animate: function( toShow, toHide, data ) {
6288 var total, easing, duration,
6291 down = toShow.length &&
6292 ( !toHide.length || ( toShow.index() < toHide.index() ) ),
6293 animate = this.options.animate || {},
6294 options = down && animate.down || animate,
6295 complete = function() {
6296 that._toggleComplete( data );
6299 if ( typeof options === "number" ) {
6302 if ( typeof options === "string" ) {
6305 // fall back from options to animation in case of partial down settings
6306 easing = easing || options.easing || animate.easing;
6307 duration = duration || options.duration || animate.duration;
6309 if ( !toHide.length ) {
6310 return toShow.animate( this.showProps, duration, easing, complete );
6312 if ( !toShow.length ) {
6313 return toHide.animate( this.hideProps, duration, easing, complete );
6316 total = toShow.show().outerHeight();
6317 toHide.animate( this.hideProps, {
6320 step: function( now, fx ) {
6321 fx.now = Math.round( now );
6326 .animate( this.showProps, {
6330 step: function( now, fx ) {
6331 fx.now = Math.round( now );
6332 if ( fx.prop !== "height" ) {
6334 } else if ( that.options.heightStyle !== "content" ) {
6335 fx.now = Math.round( total - toHide.outerHeight() - adjust );
6342 _toggleComplete: function( data ) {
6343 var toHide = data.oldPanel;
6346 .removeClass( "ui-accordion-content-active" )
6348 .removeClass( "ui-corner-top" )
6349 .addClass( "ui-corner-all" );
6351 // Work around for rendering bug in IE (#5421)
6352 if ( toHide.length ) {
6353 toHide.parent()[ 0 ].className = toHide.parent()[ 0 ].className;
6355 this._trigger( "activate", null, data );
6361 * jQuery UI Menu 1.11.3
6362 * http://jqueryui.com
6364 * Copyright jQuery Foundation and other contributors
6365 * Released under the MIT license.
6366 * http://jquery.org/license
6368 * http://api.jqueryui.com/menu/
6372 var menu = $.widget( "ui.menu", {
6374 defaultElement: "<ul>",
6378 submenu: "ui-icon-carat-1-e"
6394 _create: function() {
6395 this.activeMenu = this.element;
6397 // Flag used to prevent firing of the click handler
6398 // as the event bubbles up through nested menus
6399 this.mouseHandled = false;
6402 .addClass( "ui-menu ui-widget ui-widget-content" )
6403 .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length )
6405 role: this.options.role,
6409 if ( this.options.disabled ) {
6411 .addClass( "ui-state-disabled" )
6412 .attr( "aria-disabled", "true" );
6416 // Prevent focus from sticking to links inside menu after clicking
6417 // them (focus should always stay on UL during navigation).
6418 "mousedown .ui-menu-item": function( event ) {
6419 event.preventDefault();
6421 "click .ui-menu-item": function( event ) {
6422 var target = $( event.target );
6423 if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
6424 this.select( event );
6426 // Only set the mouseHandled flag if the event will bubble, see #9469.
6427 if ( !event.isPropagationStopped() ) {
6428 this.mouseHandled = true;
6431 // Open submenu on click
6432 if ( target.has( ".ui-menu" ).length ) {
6433 this.expand( event );
6434 } else if ( !this.element.is( ":focus" ) && $( this.document[ 0 ].activeElement ).closest( ".ui-menu" ).length ) {
6436 // Redirect focus to the menu
6437 this.element.trigger( "focus", [ true ] );
6439 // If the active item is on the top level, let it stay active.
6440 // Otherwise, blur the active item since it is no longer visible.
6441 if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
6442 clearTimeout( this.timer );
6447 "mouseenter .ui-menu-item": function( event ) {
6448 // Ignore mouse events while typeahead is active, see #10458.
6449 // Prevents focusing the wrong item when typeahead causes a scroll while the mouse
6450 // is over an item in the menu
6451 if ( this.previousFilter ) {
6454 var target = $( event.currentTarget );
6455 // Remove ui-state-active class from siblings of the newly focused menu item
6456 // to avoid a jump caused by adjacent elements both having a class with a border
6457 target.siblings( ".ui-state-active" ).removeClass( "ui-state-active" );
6458 this.focus( event, target );
6460 mouseleave: "collapseAll",
6461 "mouseleave .ui-menu": "collapseAll",
6462 focus: function( event, keepActiveItem ) {
6463 // If there's already an active item, keep it active
6464 // If not, activate the first item
6465 var item = this.active || this.element.find( this.options.items ).eq( 0 );
6467 if ( !keepActiveItem ) {
6468 this.focus( event, item );
6471 blur: function( event ) {
6472 this._delay(function() {
6473 if ( !$.contains( this.element[0], this.document[0].activeElement ) ) {
6474 this.collapseAll( event );
6483 // Clicks outside of a menu collapse any open menus
6484 this._on( this.document, {
6485 click: function( event ) {
6486 if ( this._closeOnDocumentClick( event ) ) {
6487 this.collapseAll( event );
6490 // Reset the mouseHandled flag
6491 this.mouseHandled = false;
6496 _destroy: function() {
6497 // Destroy (sub)menus
6499 .removeAttr( "aria-activedescendant" )
6500 .find( ".ui-menu" ).addBack()
6501 .removeClass( "ui-menu ui-widget ui-widget-content ui-menu-icons ui-front" )
6502 .removeAttr( "role" )
6503 .removeAttr( "tabIndex" )
6504 .removeAttr( "aria-labelledby" )
6505 .removeAttr( "aria-expanded" )
6506 .removeAttr( "aria-hidden" )
6507 .removeAttr( "aria-disabled" )
6511 // Destroy menu items
6512 this.element.find( ".ui-menu-item" )
6513 .removeClass( "ui-menu-item" )
6514 .removeAttr( "role" )
6515 .removeAttr( "aria-disabled" )
6517 .removeClass( "ui-state-hover" )
6518 .removeAttr( "tabIndex" )
6519 .removeAttr( "role" )
6520 .removeAttr( "aria-haspopup" )
6521 .children().each( function() {
6522 var elem = $( this );
6523 if ( elem.data( "ui-menu-submenu-carat" ) ) {
6528 // Destroy menu dividers
6529 this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" );
6532 _keydown: function( event ) {
6533 var match, prev, character, skip,
6534 preventDefault = true;
6536 switch ( event.keyCode ) {
6537 case $.ui.keyCode.PAGE_UP:
6538 this.previousPage( event );
6540 case $.ui.keyCode.PAGE_DOWN:
6541 this.nextPage( event );
6543 case $.ui.keyCode.HOME:
6544 this._move( "first", "first", event );
6546 case $.ui.keyCode.END:
6547 this._move( "last", "last", event );
6549 case $.ui.keyCode.UP:
6550 this.previous( event );
6552 case $.ui.keyCode.DOWN:
6555 case $.ui.keyCode.LEFT:
6556 this.collapse( event );
6558 case $.ui.keyCode.RIGHT:
6559 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
6560 this.expand( event );
6563 case $.ui.keyCode.ENTER:
6564 case $.ui.keyCode.SPACE:
6565 this._activate( event );
6567 case $.ui.keyCode.ESCAPE:
6568 this.collapse( event );
6571 preventDefault = false;
6572 prev = this.previousFilter || "";
6573 character = String.fromCharCode( event.keyCode );
6576 clearTimeout( this.filterTimer );
6578 if ( character === prev ) {
6581 character = prev + character;
6584 match = this._filterMenuItems( character );
6585 match = skip && match.index( this.active.next() ) !== -1 ?
6586 this.active.nextAll( ".ui-menu-item" ) :
6589 // If no matches on the current filter, reset to the last character pressed
6590 // to move down the menu to the first item that starts with that character
6591 if ( !match.length ) {
6592 character = String.fromCharCode( event.keyCode );
6593 match = this._filterMenuItems( character );
6596 if ( match.length ) {
6597 this.focus( event, match );
6598 this.previousFilter = character;
6599 this.filterTimer = this._delay(function() {
6600 delete this.previousFilter;
6603 delete this.previousFilter;
6607 if ( preventDefault ) {
6608 event.preventDefault();
6612 _activate: function( event ) {
6613 if ( !this.active.is( ".ui-state-disabled" ) ) {
6614 if ( this.active.is( "[aria-haspopup='true']" ) ) {
6615 this.expand( event );
6617 this.select( event );
6622 refresh: function() {
6625 icon = this.options.icons.submenu,
6626 submenus = this.element.find( this.options.menus );
6628 this.element.toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length );
6630 // Initialize nested menus
6631 submenus.filter( ":not(.ui-menu)" )
6632 .addClass( "ui-menu ui-widget ui-widget-content ui-front" )
6635 role: this.options.role,
6636 "aria-hidden": "true",
6637 "aria-expanded": "false"
6640 var menu = $( this ),
6641 item = menu.parent(),
6642 submenuCarat = $( "<span>" )
6643 .addClass( "ui-menu-icon ui-icon " + icon )
6644 .data( "ui-menu-submenu-carat", true );
6647 .attr( "aria-haspopup", "true" )
6648 .prepend( submenuCarat );
6649 menu.attr( "aria-labelledby", item.attr( "id" ) );
6652 menus = submenus.add( this.element );
6653 items = menus.find( this.options.items );
6655 // Initialize menu-items containing spaces and/or dashes only as dividers
6656 items.not( ".ui-menu-item" ).each(function() {
6657 var item = $( this );
6658 if ( that._isDivider( item ) ) {
6659 item.addClass( "ui-widget-content ui-menu-divider" );
6663 // Don't refresh list items that are already adapted
6664 items.not( ".ui-menu-item, .ui-menu-divider" )
6665 .addClass( "ui-menu-item" )
6669 role: this._itemRole()
6672 // Add aria-disabled attribute to any disabled menu item
6673 items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
6675 // If the active item has been removed, blur the menu
6676 if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
6681 _itemRole: function() {
6685 }[ this.options.role ];
6688 _setOption: function( key, value ) {
6689 if ( key === "icons" ) {
6690 this.element.find( ".ui-menu-icon" )
6691 .removeClass( this.options.icons.submenu )
6692 .addClass( value.submenu );
6694 if ( key === "disabled" ) {
6696 .toggleClass( "ui-state-disabled", !!value )
6697 .attr( "aria-disabled", value );
6699 this._super( key, value );
6702 focus: function( event, item ) {
6703 var nested, focused;
6704 this.blur( event, event && event.type === "focus" );
6706 this._scrollIntoView( item );
6708 this.active = item.first();
6709 focused = this.active.addClass( "ui-state-focus" ).removeClass( "ui-state-active" );
6710 // Only update aria-activedescendant if there's a role
6711 // otherwise we assume focus is managed elsewhere
6712 if ( this.options.role ) {
6713 this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
6716 // Highlight active parent menu item, if any
6719 .closest( ".ui-menu-item" )
6720 .addClass( "ui-state-active" );
6722 if ( event && event.type === "keydown" ) {
6725 this.timer = this._delay(function() {
6730 nested = item.children( ".ui-menu" );
6731 if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) {
6732 this._startOpening(nested);
6734 this.activeMenu = item.parent();
6736 this._trigger( "focus", event, { item: item } );
6739 _scrollIntoView: function( item ) {
6740 var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
6741 if ( this._hasScroll() ) {
6742 borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0;
6743 paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0;
6744 offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
6745 scroll = this.activeMenu.scrollTop();
6746 elementHeight = this.activeMenu.height();
6747 itemHeight = item.outerHeight();
6750 this.activeMenu.scrollTop( scroll + offset );
6751 } else if ( offset + itemHeight > elementHeight ) {
6752 this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
6757 blur: function( event, fromFocus ) {
6759 clearTimeout( this.timer );
6762 if ( !this.active ) {
6766 this.active.removeClass( "ui-state-focus" );
6769 this._trigger( "blur", event, { item: this.active } );
6772 _startOpening: function( submenu ) {
6773 clearTimeout( this.timer );
6775 // Don't open if already open fixes a Firefox bug that caused a .5 pixel
6776 // shift in the submenu position when mousing over the carat icon
6777 if ( submenu.attr( "aria-hidden" ) !== "true" ) {
6781 this.timer = this._delay(function() {
6783 this._open( submenu );
6787 _open: function( submenu ) {
6788 var position = $.extend({
6790 }, this.options.position );
6792 clearTimeout( this.timer );
6793 this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
6795 .attr( "aria-hidden", "true" );
6799 .removeAttr( "aria-hidden" )
6800 .attr( "aria-expanded", "true" )
6801 .position( position );
6804 collapseAll: function( event, all ) {
6805 clearTimeout( this.timer );
6806 this.timer = this._delay(function() {
6807 // If we were passed an event, look for the submenu that contains the event
6808 var currentMenu = all ? this.element :
6809 $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
6811 // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway
6812 if ( !currentMenu.length ) {
6813 currentMenu = this.element;
6816 this._close( currentMenu );
6819 this.activeMenu = currentMenu;
6823 // With no arguments, closes the currently active menu - if nothing is active
6824 // it closes all menus. If passed an argument, it will search for menus BELOW
6825 _close: function( startMenu ) {
6827 startMenu = this.active ? this.active.parent() : this.element;
6833 .attr( "aria-hidden", "true" )
6834 .attr( "aria-expanded", "false" )
6836 .find( ".ui-state-active" ).not( ".ui-state-focus" )
6837 .removeClass( "ui-state-active" );
6840 _closeOnDocumentClick: function( event ) {
6841 return !$( event.target ).closest( ".ui-menu" ).length;
6844 _isDivider: function( item ) {
6846 // Match hyphen, em dash, en dash
6847 return !/[^\-\u2014\u2013\s]/.test( item.text() );
6850 collapse: function( event ) {
6851 var newItem = this.active &&
6852 this.active.parent().closest( ".ui-menu-item", this.element );
6853 if ( newItem && newItem.length ) {
6855 this.focus( event, newItem );
6859 expand: function( event ) {
6860 var newItem = this.active &&
6862 .children( ".ui-menu " )
6863 .find( this.options.items )
6866 if ( newItem && newItem.length ) {
6867 this._open( newItem.parent() );
6869 // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
6870 this._delay(function() {
6871 this.focus( event, newItem );
6876 next: function( event ) {
6877 this._move( "next", "first", event );
6880 previous: function( event ) {
6881 this._move( "prev", "last", event );
6884 isFirstItem: function() {
6885 return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
6888 isLastItem: function() {
6889 return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
6892 _move: function( direction, filter, event ) {
6894 if ( this.active ) {
6895 if ( direction === "first" || direction === "last" ) {
6897 [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
6901 [ direction + "All" ]( ".ui-menu-item" )
6905 if ( !next || !next.length || !this.active ) {
6906 next = this.activeMenu.find( this.options.items )[ filter ]();
6909 this.focus( event, next );
6912 nextPage: function( event ) {
6913 var item, base, height;
6915 if ( !this.active ) {
6919 if ( this.isLastItem() ) {
6922 if ( this._hasScroll() ) {
6923 base = this.active.offset().top;
6924 height = this.element.height();
6925 this.active.nextAll( ".ui-menu-item" ).each(function() {
6927 return item.offset().top - base - height < 0;
6930 this.focus( event, item );
6932 this.focus( event, this.activeMenu.find( this.options.items )
6933 [ !this.active ? "first" : "last" ]() );
6937 previousPage: function( event ) {
6938 var item, base, height;
6939 if ( !this.active ) {
6943 if ( this.isFirstItem() ) {
6946 if ( this._hasScroll() ) {
6947 base = this.active.offset().top;
6948 height = this.element.height();
6949 this.active.prevAll( ".ui-menu-item" ).each(function() {
6951 return item.offset().top - base + height > 0;
6954 this.focus( event, item );
6956 this.focus( event, this.activeMenu.find( this.options.items ).first() );
6960 _hasScroll: function() {
6961 return this.element.outerHeight() < this.element.prop( "scrollHeight" );
6964 select: function( event ) {
6965 // TODO: It should never be possible to not have an active item at this
6966 // point, but the tests don't trigger mouseenter before click.
6967 this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
6968 var ui = { item: this.active };
6969 if ( !this.active.has( ".ui-menu" ).length ) {
6970 this.collapseAll( event, true );
6972 this._trigger( "select", event, ui );
6975 _filterMenuItems: function(character) {
6976 var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ),
6977 regex = new RegExp( "^" + escapedCharacter, "i" );
6979 return this.activeMenu
6980 .find( this.options.items )
6982 // Only match on items, not dividers or other content (#10571)
6983 .filter( ".ui-menu-item" )
6984 .filter(function() {
6985 return regex.test( $.trim( $( this ).text() ) );
6992 * jQuery UI Autocomplete 1.11.3
6993 * http://jqueryui.com
6995 * Copyright jQuery Foundation and other contributors
6996 * Released under the MIT license.
6997 * http://jquery.org/license
6999 * http://api.jqueryui.com/autocomplete/
7003 $.widget( "ui.autocomplete", {
7005 defaultElement: "<input>",
7031 _create: function() {
7032 // Some browsers only repeat keydown events, not keypress events,
7033 // so we use the suppressKeyPress flag to determine if we've already
7034 // handled the keydown event. #7269
7035 // Unfortunately the code for & in keypress is the same as the up arrow,
7036 // so we use the suppressKeyPressRepeat flag to avoid handling keypress
7037 // events when we know the keydown event was used to modify the
7038 // search term. #7799
7039 var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
7040 nodeName = this.element[ 0 ].nodeName.toLowerCase(),
7041 isTextarea = nodeName === "textarea",
7042 isInput = nodeName === "input";
7045 // Textareas are always multi-line
7047 // Inputs are always single-line, even if inside a contentEditable element
7048 // IE also treats inputs as contentEditable
7050 // All other element types are determined by whether or not they're contentEditable
7051 this.element.prop( "isContentEditable" );
7053 this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
7054 this.isNewMenu = true;
7057 .addClass( "ui-autocomplete-input" )
7058 .attr( "autocomplete", "off" );
7060 this._on( this.element, {
7061 keydown: function( event ) {
7062 if ( this.element.prop( "readOnly" ) ) {
7063 suppressKeyPress = true;
7064 suppressInput = true;
7065 suppressKeyPressRepeat = true;
7069 suppressKeyPress = false;
7070 suppressInput = false;
7071 suppressKeyPressRepeat = false;
7072 var keyCode = $.ui.keyCode;
7073 switch ( event.keyCode ) {
7074 case keyCode.PAGE_UP:
7075 suppressKeyPress = true;
7076 this._move( "previousPage", event );
7078 case keyCode.PAGE_DOWN:
7079 suppressKeyPress = true;
7080 this._move( "nextPage", event );
7083 suppressKeyPress = true;
7084 this._keyEvent( "previous", event );
7087 suppressKeyPress = true;
7088 this._keyEvent( "next", event );
7091 // when menu is open and has focus
7092 if ( this.menu.active ) {
7093 // #6055 - Opera still allows the keypress to occur
7094 // which causes forms to submit
7095 suppressKeyPress = true;
7096 event.preventDefault();
7097 this.menu.select( event );
7101 if ( this.menu.active ) {
7102 this.menu.select( event );
7105 case keyCode.ESCAPE:
7106 if ( this.menu.element.is( ":visible" ) ) {
7107 if ( !this.isMultiLine ) {
7108 this._value( this.term );
7110 this.close( event );
7111 // Different browsers have different default behavior for escape
7112 // Single press can mean undo or clear
7113 // Double press in IE means clear the whole form
7114 event.preventDefault();
7118 suppressKeyPressRepeat = true;
7119 // search timeout should be triggered before the input value is changed
7120 this._searchTimeout( event );
7124 keypress: function( event ) {
7125 if ( suppressKeyPress ) {
7126 suppressKeyPress = false;
7127 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
7128 event.preventDefault();
7132 if ( suppressKeyPressRepeat ) {
7136 // replicate some key handlers to allow them to repeat in Firefox and Opera
7137 var keyCode = $.ui.keyCode;
7138 switch ( event.keyCode ) {
7139 case keyCode.PAGE_UP:
7140 this._move( "previousPage", event );
7142 case keyCode.PAGE_DOWN:
7143 this._move( "nextPage", event );
7146 this._keyEvent( "previous", event );
7149 this._keyEvent( "next", event );
7153 input: function( event ) {
7154 if ( suppressInput ) {
7155 suppressInput = false;
7156 event.preventDefault();
7159 this._searchTimeout( event );
7162 this.selectedItem = null;
7163 this.previous = this._value();
7165 blur: function( event ) {
7166 if ( this.cancelBlur ) {
7167 delete this.cancelBlur;
7171 clearTimeout( this.searching );
7172 this.close( event );
7173 this._change( event );
7178 this.menu = $( "<ul>" )
7179 .addClass( "ui-autocomplete ui-front" )
7180 .appendTo( this._appendTo() )
7182 // disable ARIA support, the live region takes care of that
7186 .menu( "instance" );
7188 this._on( this.menu.element, {
7189 mousedown: function( event ) {
7190 // prevent moving focus out of the text field
7191 event.preventDefault();
7193 // IE doesn't prevent moving focus even with event.preventDefault()
7194 // so we set a flag to know when we should ignore the blur event
7195 this.cancelBlur = true;
7196 this._delay(function() {
7197 delete this.cancelBlur;
7200 // clicking on the scrollbar causes focus to shift to the body
7201 // but we can't detect a mouseup or a click immediately afterward
7202 // so we have to track the next mousedown and close the menu if
7203 // the user clicks somewhere outside of the autocomplete
7204 var menuElement = this.menu.element[ 0 ];
7205 if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
7206 this._delay(function() {
7208 this.document.one( "mousedown", function( event ) {
7209 if ( event.target !== that.element[ 0 ] &&
7210 event.target !== menuElement &&
7211 !$.contains( menuElement, event.target ) ) {
7218 menufocus: function( event, ui ) {
7221 // Prevent accidental activation of menu items in Firefox (#7024 #9118)
7222 if ( this.isNewMenu ) {
7223 this.isNewMenu = false;
7224 if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
7227 this.document.one( "mousemove", function() {
7228 $( event.target ).trigger( event.originalEvent );
7235 item = ui.item.data( "ui-autocomplete-item" );
7236 if ( false !== this._trigger( "focus", event, { item: item } ) ) {
7237 // use value to match what will end up in the input, if it was a key event
7238 if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
7239 this._value( item.value );
7243 // Announce the value in the liveRegion
7244 label = ui.item.attr( "aria-label" ) || item.value;
7245 if ( label && $.trim( label ).length ) {
7246 this.liveRegion.children().hide();
7247 $( "<div>" ).text( label ).appendTo( this.liveRegion );
7250 menuselect: function( event, ui ) {
7251 var item = ui.item.data( "ui-autocomplete-item" ),
7252 previous = this.previous;
7254 // only trigger when focus was lost (click on menu)
7255 if ( this.element[ 0 ] !== this.document[ 0 ].activeElement ) {
7256 this.element.focus();
7257 this.previous = previous;
7258 // #6109 - IE triggers two focus events and the second
7259 // is asynchronous, so we need to reset the previous
7260 // term synchronously and asynchronously :-(
7261 this._delay(function() {
7262 this.previous = previous;
7263 this.selectedItem = item;
7267 if ( false !== this._trigger( "select", event, { item: item } ) ) {
7268 this._value( item.value );
7270 // reset the term after the select event
7271 // this allows custom select handling to work properly
7272 this.term = this._value();
7274 this.close( event );
7275 this.selectedItem = item;
7279 this.liveRegion = $( "<span>", {
7281 "aria-live": "assertive",
7282 "aria-relevant": "additions"
7284 .addClass( "ui-helper-hidden-accessible" )
7285 .appendTo( this.document[ 0 ].body );
7287 // turning off autocomplete prevents the browser from remembering the
7288 // value when navigating through history, so we re-enable autocomplete
7289 // if the page is unloaded before the widget is destroyed. #7790
7290 this._on( this.window, {
7291 beforeunload: function() {
7292 this.element.removeAttr( "autocomplete" );
7297 _destroy: function() {
7298 clearTimeout( this.searching );
7300 .removeClass( "ui-autocomplete-input" )
7301 .removeAttr( "autocomplete" );
7302 this.menu.element.remove();
7303 this.liveRegion.remove();
7306 _setOption: function( key, value ) {
7307 this._super( key, value );
7308 if ( key === "source" ) {
7311 if ( key === "appendTo" ) {
7312 this.menu.element.appendTo( this._appendTo() );
7314 if ( key === "disabled" && value && this.xhr ) {
7319 _appendTo: function() {
7320 var element = this.options.appendTo;
7323 element = element.jquery || element.nodeType ?
7325 this.document.find( element ).eq( 0 );
7328 if ( !element || !element[ 0 ] ) {
7329 element = this.element.closest( ".ui-front" );
7332 if ( !element.length ) {
7333 element = this.document[ 0 ].body;
7339 _initSource: function() {
7342 if ( $.isArray( this.options.source ) ) {
7343 array = this.options.source;
7344 this.source = function( request, response ) {
7345 response( $.ui.autocomplete.filter( array, request.term ) );
7347 } else if ( typeof this.options.source === "string" ) {
7348 url = this.options.source;
7349 this.source = function( request, response ) {
7357 success: function( data ) {
7366 this.source = this.options.source;
7370 _searchTimeout: function( event ) {
7371 clearTimeout( this.searching );
7372 this.searching = this._delay(function() {
7374 // Search if the value has changed, or if the user retypes the same value (see #7434)
7375 var equalValues = this.term === this._value(),
7376 menuVisible = this.menu.element.is( ":visible" ),
7377 modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
7379 if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) {
7380 this.selectedItem = null;
7381 this.search( null, event );
7383 }, this.options.delay );
7386 search: function( value, event ) {
7387 value = value != null ? value : this._value();
7389 // always save the actual value, not the one passed as an argument
7390 this.term = this._value();
7392 if ( value.length < this.options.minLength ) {
7393 return this.close( event );
7396 if ( this._trigger( "search", event ) === false ) {
7400 return this._search( value );
7403 _search: function( value ) {
7405 this.element.addClass( "ui-autocomplete-loading" );
7406 this.cancelSearch = false;
7408 this.source( { term: value }, this._response() );
7411 _response: function() {
7412 var index = ++this.requestIndex;
7414 return $.proxy(function( content ) {
7415 if ( index === this.requestIndex ) {
7416 this.__response( content );
7420 if ( !this.pending ) {
7421 this.element.removeClass( "ui-autocomplete-loading" );
7426 __response: function( content ) {
7428 content = this._normalize( content );
7430 this._trigger( "response", null, { content: content } );
7431 if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
7432 this._suggest( content );
7433 this._trigger( "open" );
7435 // use ._close() instead of .close() so we don't cancel future searches
7440 close: function( event ) {
7441 this.cancelSearch = true;
7442 this._close( event );
7445 _close: function( event ) {
7446 if ( this.menu.element.is( ":visible" ) ) {
7447 this.menu.element.hide();
7449 this.isNewMenu = true;
7450 this._trigger( "close", event );
7454 _change: function( event ) {
7455 if ( this.previous !== this._value() ) {
7456 this._trigger( "change", event, { item: this.selectedItem } );
7460 _normalize: function( items ) {
7461 // assume all items have the right format when the first item is complete
7462 if ( items.length && items[ 0 ].label && items[ 0 ].value ) {
7465 return $.map( items, function( item ) {
7466 if ( typeof item === "string" ) {
7472 return $.extend( {}, item, {
7473 label: item.label || item.value,
7474 value: item.value || item.label
7479 _suggest: function( items ) {
7480 var ul = this.menu.element.empty();
7481 this._renderMenu( ul, items );
7482 this.isNewMenu = true;
7483 this.menu.refresh();
7485 // size and position menu
7488 ul.position( $.extend({
7490 }, this.options.position ) );
7492 if ( this.options.autoFocus ) {
7497 _resizeMenu: function() {
7498 var ul = this.menu.element;
7499 ul.outerWidth( Math.max(
7500 // Firefox wraps long text (possibly a rounding bug)
7501 // so we add 1px to avoid the wrapping (#7513)
7502 ul.width( "" ).outerWidth() + 1,
7503 this.element.outerWidth()
7507 _renderMenu: function( ul, items ) {
7509 $.each( items, function( index, item ) {
7510 that._renderItemData( ul, item );
7514 _renderItemData: function( ul, item ) {
7515 return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
7518 _renderItem: function( ul, item ) {
7519 return $( "<li>" ).text( item.label ).appendTo( ul );
7522 _move: function( direction, event ) {
7523 if ( !this.menu.element.is( ":visible" ) ) {
7524 this.search( null, event );
7527 if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
7528 this.menu.isLastItem() && /^next/.test( direction ) ) {
7530 if ( !this.isMultiLine ) {
7531 this._value( this.term );
7537 this.menu[ direction ]( event );
7540 widget: function() {
7541 return this.menu.element;
7544 _value: function() {
7545 return this.valueMethod.apply( this.element, arguments );
7548 _keyEvent: function( keyEvent, event ) {
7549 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
7550 this._move( keyEvent, event );
7552 // prevents moving cursor to beginning/end of the text field in some browsers
7553 event.preventDefault();
7558 $.extend( $.ui.autocomplete, {
7559 escapeRegex: function( value ) {
7560 return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
7562 filter: function( array, term ) {
7563 var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" );
7564 return $.grep( array, function( value ) {
7565 return matcher.test( value.label || value.value || value );
7570 // live region extension, adding a `messages` option
7571 // NOTE: This is an experimental API. We are still investigating
7572 // a full solution for string manipulation and internationalization.
7573 $.widget( "ui.autocomplete", $.ui.autocomplete, {
7576 noResults: "No search results.",
7577 results: function( amount ) {
7578 return amount + ( amount > 1 ? " results are" : " result is" ) +
7579 " available, use up and down arrow keys to navigate.";
7584 __response: function( content ) {
7586 this._superApply( arguments );
7587 if ( this.options.disabled || this.cancelSearch ) {
7590 if ( content && content.length ) {
7591 message = this.options.messages.results( content.length );
7593 message = this.options.messages.noResults;
7595 this.liveRegion.children().hide();
7596 $( "<div>" ).text( message ).appendTo( this.liveRegion );
7600 var autocomplete = $.ui.autocomplete;
7604 * jQuery UI Button 1.11.3
7605 * http://jqueryui.com
7607 * Copyright jQuery Foundation and other contributors
7608 * Released under the MIT license.
7609 * http://jquery.org/license
7611 * http://api.jqueryui.com/button/
7616 baseClasses = "ui-button ui-widget ui-state-default ui-corner-all",
7617 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",
7618 formResetHandler = function() {
7619 var form = $( this );
7620 setTimeout(function() {
7621 form.find( ":ui-button" ).button( "refresh" );
7624 radioGroup = function( radio ) {
7625 var name = radio.name,
7629 name = name.replace( /'/g, "\\'" );
7631 radios = $( form ).find( "[name='" + name + "'][type=radio]" );
7633 radios = $( "[name='" + name + "'][type=radio]", radio.ownerDocument )
7634 .filter(function() {
7642 $.widget( "ui.button", {
7644 defaultElement: "<button>",
7654 _create: function() {
7655 this.element.closest( "form" )
7656 .unbind( "reset" + this.eventNamespace )
7657 .bind( "reset" + this.eventNamespace, formResetHandler );
7659 if ( typeof this.options.disabled !== "boolean" ) {
7660 this.options.disabled = !!this.element.prop( "disabled" );
7662 this.element.prop( "disabled", this.options.disabled );
7665 this._determineButtonType();
7666 this.hasTitle = !!this.buttonElement.attr( "title" );
7669 options = this.options,
7670 toggleButton = this.type === "checkbox" || this.type === "radio",
7671 activeClass = !toggleButton ? "ui-state-active" : "";
7673 if ( options.label === null ) {
7674 options.label = (this.type === "input" ? this.buttonElement.val() : this.buttonElement.html());
7677 this._hoverable( this.buttonElement );
7680 .addClass( baseClasses )
7681 .attr( "role", "button" )
7682 .bind( "mouseenter" + this.eventNamespace, function() {
7683 if ( options.disabled ) {
7686 if ( this === lastActive ) {
7687 $( this ).addClass( "ui-state-active" );
7690 .bind( "mouseleave" + this.eventNamespace, function() {
7691 if ( options.disabled ) {
7694 $( this ).removeClass( activeClass );
7696 .bind( "click" + this.eventNamespace, function( event ) {
7697 if ( options.disabled ) {
7698 event.preventDefault();
7699 event.stopImmediatePropagation();
7703 // Can't use _focusable() because the element that receives focus
7704 // and the element that gets the ui-state-focus class are different
7707 this.buttonElement.addClass( "ui-state-focus" );
7710 this.buttonElement.removeClass( "ui-state-focus" );
7714 if ( toggleButton ) {
7715 this.element.bind( "change" + this.eventNamespace, function() {
7720 if ( this.type === "checkbox" ) {
7721 this.buttonElement.bind( "click" + this.eventNamespace, function() {
7722 if ( options.disabled ) {
7726 } else if ( this.type === "radio" ) {
7727 this.buttonElement.bind( "click" + this.eventNamespace, function() {
7728 if ( options.disabled ) {
7731 $( this ).addClass( "ui-state-active" );
7732 that.buttonElement.attr( "aria-pressed", "true" );
7734 var radio = that.element[ 0 ];
7738 return $( this ).button( "widget" )[ 0 ];
7740 .removeClass( "ui-state-active" )
7741 .attr( "aria-pressed", "false" );
7745 .bind( "mousedown" + this.eventNamespace, function() {
7746 if ( options.disabled ) {
7749 $( this ).addClass( "ui-state-active" );
7751 that.document.one( "mouseup", function() {
7755 .bind( "mouseup" + this.eventNamespace, function() {
7756 if ( options.disabled ) {
7759 $( this ).removeClass( "ui-state-active" );
7761 .bind( "keydown" + this.eventNamespace, function(event) {
7762 if ( options.disabled ) {
7765 if ( event.keyCode === $.ui.keyCode.SPACE || event.keyCode === $.ui.keyCode.ENTER ) {
7766 $( this ).addClass( "ui-state-active" );
7769 // see #8559, we bind to blur here in case the button element loses
7770 // focus between keydown and keyup, it would be left in an "active" state
7771 .bind( "keyup" + this.eventNamespace + " blur" + this.eventNamespace, function() {
7772 $( this ).removeClass( "ui-state-active" );
7775 if ( this.buttonElement.is("a") ) {
7776 this.buttonElement.keyup(function(event) {
7777 if ( event.keyCode === $.ui.keyCode.SPACE ) {
7778 // TODO pass through original event correctly (just as 2nd argument doesn't work)
7785 this._setOption( "disabled", options.disabled );
7786 this._resetButton();
7789 _determineButtonType: function() {
7790 var ancestor, labelSelector, checked;
7792 if ( this.element.is("[type=checkbox]") ) {
7793 this.type = "checkbox";
7794 } else if ( this.element.is("[type=radio]") ) {
7795 this.type = "radio";
7796 } else if ( this.element.is("input") ) {
7797 this.type = "input";
7799 this.type = "button";
7802 if ( this.type === "checkbox" || this.type === "radio" ) {
7803 // we don't search against the document in case the element
7804 // is disconnected from the DOM
7805 ancestor = this.element.parents().last();
7806 labelSelector = "label[for='" + this.element.attr("id") + "']";
7807 this.buttonElement = ancestor.find( labelSelector );
7808 if ( !this.buttonElement.length ) {
7809 ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings();
7810 this.buttonElement = ancestor.filter( labelSelector );
7811 if ( !this.buttonElement.length ) {
7812 this.buttonElement = ancestor.find( labelSelector );
7815 this.element.addClass( "ui-helper-hidden-accessible" );
7817 checked = this.element.is( ":checked" );
7819 this.buttonElement.addClass( "ui-state-active" );
7821 this.buttonElement.prop( "aria-pressed", checked );
7823 this.buttonElement = this.element;
7827 widget: function() {
7828 return this.buttonElement;
7831 _destroy: function() {
7833 .removeClass( "ui-helper-hidden-accessible" );
7835 .removeClass( baseClasses + " ui-state-active " + typeClasses )
7836 .removeAttr( "role" )
7837 .removeAttr( "aria-pressed" )
7838 .html( this.buttonElement.find(".ui-button-text").html() );
7840 if ( !this.hasTitle ) {
7841 this.buttonElement.removeAttr( "title" );
7845 _setOption: function( key, value ) {
7846 this._super( key, value );
7847 if ( key === "disabled" ) {
7848 this.widget().toggleClass( "ui-state-disabled", !!value );
7849 this.element.prop( "disabled", !!value );
7851 if ( this.type === "checkbox" || this.type === "radio" ) {
7852 this.buttonElement.removeClass( "ui-state-focus" );
7854 this.buttonElement.removeClass( "ui-state-focus ui-state-active" );
7859 this._resetButton();
7862 refresh: function() {
7864 var isDisabled = this.element.is( "input, button" ) ? this.element.is( ":disabled" ) : this.element.hasClass( "ui-button-disabled" );
7866 if ( isDisabled !== this.options.disabled ) {
7867 this._setOption( "disabled", isDisabled );
7869 if ( this.type === "radio" ) {
7870 radioGroup( this.element[0] ).each(function() {
7871 if ( $( this ).is( ":checked" ) ) {
7872 $( this ).button( "widget" )
7873 .addClass( "ui-state-active" )
7874 .attr( "aria-pressed", "true" );
7876 $( this ).button( "widget" )
7877 .removeClass( "ui-state-active" )
7878 .attr( "aria-pressed", "false" );
7881 } else if ( this.type === "checkbox" ) {
7882 if ( this.element.is( ":checked" ) ) {
7884 .addClass( "ui-state-active" )
7885 .attr( "aria-pressed", "true" );
7888 .removeClass( "ui-state-active" )
7889 .attr( "aria-pressed", "false" );
7894 _resetButton: function() {
7895 if ( this.type === "input" ) {
7896 if ( this.options.label ) {
7897 this.element.val( this.options.label );
7901 var buttonElement = this.buttonElement.removeClass( typeClasses ),
7902 buttonText = $( "<span></span>", this.document[0] )
7903 .addClass( "ui-button-text" )
7904 .html( this.options.label )
7905 .appendTo( buttonElement.empty() )
7907 icons = this.options.icons,
7908 multipleIcons = icons.primary && icons.secondary,
7911 if ( icons.primary || icons.secondary ) {
7912 if ( this.options.text ) {
7913 buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) );
7916 if ( icons.primary ) {
7917 buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" );
7920 if ( icons.secondary ) {
7921 buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" );
7924 if ( !this.options.text ) {
7925 buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" );
7927 if ( !this.hasTitle ) {
7928 buttonElement.attr( "title", $.trim( buttonText ) );
7932 buttonClasses.push( "ui-button-text-only" );
7934 buttonElement.addClass( buttonClasses.join( " " ) );
7938 $.widget( "ui.buttonset", {
7941 items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)"
7944 _create: function() {
7945 this.element.addClass( "ui-buttonset" );
7952 _setOption: function( key, value ) {
7953 if ( key === "disabled" ) {
7954 this.buttons.button( "option", key, value );
7957 this._super( key, value );
7960 refresh: function() {
7961 var rtl = this.element.css( "direction" ) === "rtl",
7962 allButtons = this.element.find( this.options.items ),
7963 existingButtons = allButtons.filter( ":ui-button" );
7965 // Initialize new buttons
7966 allButtons.not( ":ui-button" ).button();
7968 // Refresh existing buttons
7969 existingButtons.button( "refresh" );
7971 this.buttons = allButtons
7973 return $( this ).button( "widget" )[ 0 ];
7975 .removeClass( "ui-corner-all ui-corner-left ui-corner-right" )
7977 .addClass( rtl ? "ui-corner-right" : "ui-corner-left" )
7980 .addClass( rtl ? "ui-corner-left" : "ui-corner-right" )
7985 _destroy: function() {
7986 this.element.removeClass( "ui-buttonset" );
7989 return $( this ).button( "widget" )[ 0 ];
7991 .removeClass( "ui-corner-left ui-corner-right" )
7993 .button( "destroy" );
7997 var button = $.ui.button;
8001 * jQuery UI Datepicker 1.11.3
8002 * http://jqueryui.com
8004 * Copyright jQuery Foundation and other contributors
8005 * Released under the MIT license.
8006 * http://jquery.org/license
8008 * http://api.jqueryui.com/datepicker/
8012 $.extend($.ui, { datepicker: { version: "1.11.3" } });
8014 var datepicker_instActive;
8016 function datepicker_getZindex( elem ) {
8017 var position, value;
8018 while ( elem.length && elem[ 0 ] !== document ) {
8019 // Ignore z-index if position is set to a value where z-index is ignored by the browser
8020 // This makes behavior of this function consistent across browsers
8021 // WebKit always returns auto if the element is positioned
8022 position = elem.css( "position" );
8023 if ( position === "absolute" || position === "relative" || position === "fixed" ) {
8024 // IE returns 0 when zIndex is not specified
8025 // other browsers return a string
8026 // we ignore the case of nested elements with an explicit value of 0
8027 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
8028 value = parseInt( elem.css( "zIndex" ), 10 );
8029 if ( !isNaN( value ) && value !== 0 ) {
8033 elem = elem.parent();
8038 /* Date picker manager.
8039 Use the singleton instance of this class, $.datepicker, to interact with the date picker.
8040 Settings for (groups of) date pickers are maintained in an instance object,
8041 allowing multiple different settings on the same page. */
8043 function Datepicker() {
8044 this._curInst = null; // The current instance in use
8045 this._keyEvent = false; // If the last event was a key event
8046 this._disabledInputs = []; // List of date picker inputs that have been disabled
8047 this._datepickerShowing = false; // True if the popup picker is showing , false if not
8048 this._inDialog = false; // True if showing within a "dialog", false if not
8049 this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
8050 this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
8051 this._appendClass = "ui-datepicker-append"; // The name of the append marker class
8052 this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
8053 this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
8054 this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
8055 this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
8056 this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
8057 this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
8058 this.regional = []; // Available regional settings, indexed by language code
8059 this.regional[""] = { // Default regional settings
8060 closeText: "Done", // Display text for close link
8061 prevText: "Prev", // Display text for previous month link
8062 nextText: "Next", // Display text for next month link
8063 currentText: "Today", // Display text for current month link
8064 monthNames: ["January","February","March","April","May","June",
8065 "July","August","September","October","November","December"], // Names of months for drop-down and formatting
8066 monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting
8067 dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting
8068 dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting
8069 dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday
8070 weekHeader: "Wk", // Column header for week of the year
8071 dateFormat: "mm/dd/yy", // See format options on parseDate
8072 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
8073 isRTL: false, // True if right-to-left language, false if left-to-right
8074 showMonthAfterYear: false, // True if the year select precedes month, false for month then year
8075 yearSuffix: "" // Additional text to append to the year in the month headers
8077 this._defaults = { // Global defaults for all the date picker instances
8078 showOn: "focus", // "focus" for popup on focus,
8079 // "button" for trigger button, or "both" for either
8080 showAnim: "fadeIn", // Name of jQuery animation for popup
8081 showOptions: {}, // Options for enhanced animations
8082 defaultDate: null, // Used when field is blank: actual date,
8083 // +/-number for offset from today, null for today
8084 appendText: "", // Display text following the input box, e.g. showing the format
8085 buttonText: "...", // Text for trigger button
8086 buttonImage: "", // URL for trigger button image
8087 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
8088 hideIfNoPrevNext: false, // True to hide next/previous month links
8089 // if not applicable, false to just disable them
8090 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
8091 gotoCurrent: false, // True if today link goes back to current selection instead
8092 changeMonth: false, // True if month can be selected directly, false if only prev/next
8093 changeYear: false, // True if year can be selected directly, false if only prev/next
8094 yearRange: "c-10:c+10", // Range of years to display in drop-down,
8095 // either relative to today's year (-nn:+nn), relative to currently displayed year
8096 // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
8097 showOtherMonths: false, // True to show dates in other months, false to leave blank
8098 selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
8099 showWeek: false, // True to show week of the year, false to not show it
8100 calculateWeek: this.iso8601Week, // How to calculate the week of the year,
8101 // takes a Date and returns the number of the week for it
8102 shortYearCutoff: "+10", // Short year values < this are in the current century,
8103 // > this are in the previous century,
8104 // string value starting with "+" for current year + value
8105 minDate: null, // The earliest selectable date, or null for no limit
8106 maxDate: null, // The latest selectable date, or null for no limit
8107 duration: "fast", // Duration of display/closure
8108 beforeShowDay: null, // Function that takes a date and returns an array with
8109 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
8110 // [2] = cell title (optional), e.g. $.datepicker.noWeekends
8111 beforeShow: null, // Function that takes an input field and
8112 // returns a set of custom settings for the date picker
8113 onSelect: null, // Define a callback function when a date is selected
8114 onChangeMonthYear: null, // Define a callback function when the month or year is changed
8115 onClose: null, // Define a callback function when the datepicker is closed
8116 numberOfMonths: 1, // Number of months to show at a time
8117 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
8118 stepMonths: 1, // Number of months to step back/forward
8119 stepBigMonths: 12, // Number of months to step back/forward for the big links
8120 altField: "", // Selector for an alternate field to store selected dates into
8121 altFormat: "", // The date format to use for the alternate field
8122 constrainInput: true, // The input is constrained by the current date format
8123 showButtonPanel: false, // True to show button panel, false to not show it
8124 autoSize: false, // True to size the input for the date format, false to leave as is
8125 disabled: false // The initial disabled state
8127 $.extend(this._defaults, this.regional[""]);
8128 this.regional.en = $.extend( true, {}, this.regional[ "" ]);
8129 this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en );
8130 this.dpDiv = datepicker_bindHover($("<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"));
8133 $.extend(Datepicker.prototype, {
8134 /* Class name added to elements to indicate already configured with a date picker. */
8135 markerClassName: "hasDatepicker",
8137 //Keep track of the maximum number of rows displayed (see #7043)
8140 // TODO rename to "widget" when switching to widget factory
8141 _widgetDatepicker: function() {
8145 /* Override the default settings for all instances of the date picker.
8146 * @param settings object - the new settings to use as defaults (anonymous object)
8147 * @return the manager object
8149 setDefaults: function(settings) {
8150 datepicker_extendRemove(this._defaults, settings || {});
8154 /* Attach the date picker to a jQuery selection.
8155 * @param target element - the target input field or division or span
8156 * @param settings object - the new settings to use for this date picker instance (anonymous)
8158 _attachDatepicker: function(target, settings) {
8159 var nodeName, inline, inst;
8160 nodeName = target.nodeName.toLowerCase();
8161 inline = (nodeName === "div" || nodeName === "span");
8164 target.id = "dp" + this.uuid;
8166 inst = this._newInst($(target), inline);
8167 inst.settings = $.extend({}, settings || {});
8168 if (nodeName === "input") {
8169 this._connectDatepicker(target, inst);
8170 } else if (inline) {
8171 this._inlineDatepicker(target, inst);
8175 /* Create a new instance object. */
8176 _newInst: function(target, inline) {
8177 var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars
8178 return {id: id, input: target, // associated target
8179 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
8180 drawMonth: 0, drawYear: 0, // month being drawn
8181 inline: inline, // is datepicker inline or not
8182 dpDiv: (!inline ? this.dpDiv : // presentation div
8183 datepicker_bindHover($("<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))};
8186 /* Attach the date picker to an input field. */
8187 _connectDatepicker: function(target, inst) {
8188 var input = $(target);
8189 inst.append = $([]);
8190 inst.trigger = $([]);
8191 if (input.hasClass(this.markerClassName)) {
8194 this._attachments(input, inst);
8195 input.addClass(this.markerClassName).keydown(this._doKeyDown).
8196 keypress(this._doKeyPress).keyup(this._doKeyUp);
8197 this._autoSize(inst);
8198 $.data(target, "datepicker", inst);
8199 //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
8200 if( inst.settings.disabled ) {
8201 this._disableDatepicker( target );
8205 /* Make attachments based on settings. */
8206 _attachments: function(input, inst) {
8207 var showOn, buttonText, buttonImage,
8208 appendText = this._get(inst, "appendText"),
8209 isRTL = this._get(inst, "isRTL");
8212 inst.append.remove();
8215 inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>");
8216 input[isRTL ? "before" : "after"](inst.append);
8219 input.unbind("focus", this._showDatepicker);
8222 inst.trigger.remove();
8225 showOn = this._get(inst, "showOn");
8226 if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field
8227 input.focus(this._showDatepicker);
8229 if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked
8230 buttonText = this._get(inst, "buttonText");
8231 buttonImage = this._get(inst, "buttonImage");
8232 inst.trigger = $(this._get(inst, "buttonImageOnly") ?
8233 $("<img/>").addClass(this._triggerClass).
8234 attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
8235 $("<button type='button'></button>").addClass(this._triggerClass).
8236 html(!buttonImage ? buttonText : $("<img/>").attr(
8237 { src:buttonImage, alt:buttonText, title:buttonText })));
8238 input[isRTL ? "before" : "after"](inst.trigger);
8239 inst.trigger.click(function() {
8240 if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) {
8241 $.datepicker._hideDatepicker();
8242 } else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) {
8243 $.datepicker._hideDatepicker();
8244 $.datepicker._showDatepicker(input[0]);
8246 $.datepicker._showDatepicker(input[0]);
8253 /* Apply the maximum length for the date format. */
8254 _autoSize: function(inst) {
8255 if (this._get(inst, "autoSize") && !inst.inline) {
8256 var findMax, max, maxI, i,
8257 date = new Date(2009, 12 - 1, 20), // Ensure double digits
8258 dateFormat = this._get(inst, "dateFormat");
8260 if (dateFormat.match(/[DM]/)) {
8261 findMax = function(names) {
8264 for (i = 0; i < names.length; i++) {
8265 if (names[i].length > max) {
8266 max = names[i].length;
8272 date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
8273 "monthNames" : "monthNamesShort"))));
8274 date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
8275 "dayNames" : "dayNamesShort"))) + 20 - date.getDay());
8277 inst.input.attr("size", this._formatDate(inst, date).length);
8281 /* Attach an inline date picker to a div. */
8282 _inlineDatepicker: function(target, inst) {
8283 var divSpan = $(target);
8284 if (divSpan.hasClass(this.markerClassName)) {
8287 divSpan.addClass(this.markerClassName).append(inst.dpDiv);
8288 $.data(target, "datepicker", inst);
8289 this._setDate(inst, this._getDefaultDate(inst), true);
8290 this._updateDatepicker(inst);
8291 this._updateAlternate(inst);
8292 //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
8293 if( inst.settings.disabled ) {
8294 this._disableDatepicker( target );
8296 // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
8297 // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
8298 inst.dpDiv.css( "display", "block" );
8301 /* Pop-up the date picker in a "dialog" box.
8302 * @param input element - ignored
8303 * @param date string or Date - the initial date to display
8304 * @param onSelect function - the function to call when a date is selected
8305 * @param settings object - update the dialog date picker instance's settings (anonymous object)
8306 * @param pos int[2] - coordinates for the dialog's position within the screen or
8307 * event - with x/y coordinates or
8308 * leave empty for default (screen centre)
8309 * @return the manager object
8311 _dialogDatepicker: function(input, date, onSelect, settings, pos) {
8312 var id, browserWidth, browserHeight, scrollX, scrollY,
8313 inst = this._dialogInst; // internal instance
8317 id = "dp" + this.uuid;
8318 this._dialogInput = $("<input type='text' id='" + id +
8319 "' style='position: absolute; top: -100px; width: 0px;'/>");
8320 this._dialogInput.keydown(this._doKeyDown);
8321 $("body").append(this._dialogInput);
8322 inst = this._dialogInst = this._newInst(this._dialogInput, false);
8324 $.data(this._dialogInput[0], "datepicker", inst);
8326 datepicker_extendRemove(inst.settings, settings || {});
8327 date = (date && date.constructor === Date ? this._formatDate(inst, date) : date);
8328 this._dialogInput.val(date);
8330 this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
8332 browserWidth = document.documentElement.clientWidth;
8333 browserHeight = document.documentElement.clientHeight;
8334 scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
8335 scrollY = document.documentElement.scrollTop || document.body.scrollTop;
8336 this._pos = // should use actual width/height below
8337 [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
8340 // move input on screen for focus, but hidden behind dialog
8341 this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px");
8342 inst.settings.onSelect = onSelect;
8343 this._inDialog = true;
8344 this.dpDiv.addClass(this._dialogClass);
8345 this._showDatepicker(this._dialogInput[0]);
8347 $.blockUI(this.dpDiv);
8349 $.data(this._dialogInput[0], "datepicker", inst);
8353 /* Detach a datepicker from its control.
8354 * @param target element - the target input field or division or span
8356 _destroyDatepicker: function(target) {
8358 $target = $(target),
8359 inst = $.data(target, "datepicker");
8361 if (!$target.hasClass(this.markerClassName)) {
8365 nodeName = target.nodeName.toLowerCase();
8366 $.removeData(target, "datepicker");
8367 if (nodeName === "input") {
8368 inst.append.remove();
8369 inst.trigger.remove();
8370 $target.removeClass(this.markerClassName).
8371 unbind("focus", this._showDatepicker).
8372 unbind("keydown", this._doKeyDown).
8373 unbind("keypress", this._doKeyPress).
8374 unbind("keyup", this._doKeyUp);
8375 } else if (nodeName === "div" || nodeName === "span") {
8376 $target.removeClass(this.markerClassName).empty();
8379 if ( datepicker_instActive === inst ) {
8380 datepicker_instActive = null;
8384 /* Enable the date picker to a jQuery selection.
8385 * @param target element - the target input field or division or span
8387 _enableDatepicker: function(target) {
8388 var nodeName, inline,
8389 $target = $(target),
8390 inst = $.data(target, "datepicker");
8392 if (!$target.hasClass(this.markerClassName)) {
8396 nodeName = target.nodeName.toLowerCase();
8397 if (nodeName === "input") {
8398 target.disabled = false;
8399 inst.trigger.filter("button").
8400 each(function() { this.disabled = false; }).end().
8401 filter("img").css({opacity: "1.0", cursor: ""});
8402 } else if (nodeName === "div" || nodeName === "span") {
8403 inline = $target.children("." + this._inlineClass);
8404 inline.children().removeClass("ui-state-disabled");
8405 inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
8406 prop("disabled", false);
8408 this._disabledInputs = $.map(this._disabledInputs,
8409 function(value) { return (value === target ? null : value); }); // delete entry
8412 /* Disable the date picker to a jQuery selection.
8413 * @param target element - the target input field or division or span
8415 _disableDatepicker: function(target) {
8416 var nodeName, inline,
8417 $target = $(target),
8418 inst = $.data(target, "datepicker");
8420 if (!$target.hasClass(this.markerClassName)) {
8424 nodeName = target.nodeName.toLowerCase();
8425 if (nodeName === "input") {
8426 target.disabled = true;
8427 inst.trigger.filter("button").
8428 each(function() { this.disabled = true; }).end().
8429 filter("img").css({opacity: "0.5", cursor: "default"});
8430 } else if (nodeName === "div" || nodeName === "span") {
8431 inline = $target.children("." + this._inlineClass);
8432 inline.children().addClass("ui-state-disabled");
8433 inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
8434 prop("disabled", true);
8436 this._disabledInputs = $.map(this._disabledInputs,
8437 function(value) { return (value === target ? null : value); }); // delete entry
8438 this._disabledInputs[this._disabledInputs.length] = target;
8441 /* Is the first field in a jQuery collection disabled as a datepicker?
8442 * @param target element - the target input field or division or span
8443 * @return boolean - true if disabled, false if enabled
8445 _isDisabledDatepicker: function(target) {
8449 for (var i = 0; i < this._disabledInputs.length; i++) {
8450 if (this._disabledInputs[i] === target) {
8457 /* Retrieve the instance data for the target control.
8458 * @param target element - the target input field or division or span
8459 * @return object - the associated instance data
8460 * @throws error if a jQuery problem getting data
8462 _getInst: function(target) {
8464 return $.data(target, "datepicker");
8467 throw "Missing instance data for this datepicker";
8471 /* Update or retrieve the settings for a date picker attached to an input field or division.
8472 * @param target element - the target input field or division or span
8473 * @param name object - the new settings to update or
8474 * string - the name of the setting to change or retrieve,
8475 * when retrieving also "all" for all instance settings or
8476 * "defaults" for all global defaults
8477 * @param value any - the new value for the setting
8478 * (omit if above is an object or to retrieve a value)
8480 _optionDatepicker: function(target, name, value) {
8481 var settings, date, minDate, maxDate,
8482 inst = this._getInst(target);
8484 if (arguments.length === 2 && typeof name === "string") {
8485 return (name === "defaults" ? $.extend({}, $.datepicker._defaults) :
8486 (inst ? (name === "all" ? $.extend({}, inst.settings) :
8487 this._get(inst, name)) : null));
8490 settings = name || {};
8491 if (typeof name === "string") {
8493 settings[name] = value;
8497 if (this._curInst === inst) {
8498 this._hideDatepicker();
8501 date = this._getDateDatepicker(target, true);
8502 minDate = this._getMinMaxDate(inst, "min");
8503 maxDate = this._getMinMaxDate(inst, "max");
8504 datepicker_extendRemove(inst.settings, settings);
8505 // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
8506 if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) {
8507 inst.settings.minDate = this._formatDate(inst, minDate);
8509 if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) {
8510 inst.settings.maxDate = this._formatDate(inst, maxDate);
8512 if ( "disabled" in settings ) {
8513 if ( settings.disabled ) {
8514 this._disableDatepicker(target);
8516 this._enableDatepicker(target);
8519 this._attachments($(target), inst);
8520 this._autoSize(inst);
8521 this._setDate(inst, date);
8522 this._updateAlternate(inst);
8523 this._updateDatepicker(inst);
8527 // change method deprecated
8528 _changeDatepicker: function(target, name, value) {
8529 this._optionDatepicker(target, name, value);
8532 /* Redraw the date picker attached to an input field or division.
8533 * @param target element - the target input field or division or span
8535 _refreshDatepicker: function(target) {
8536 var inst = this._getInst(target);
8538 this._updateDatepicker(inst);
8542 /* Set the dates for a jQuery selection.
8543 * @param target element - the target input field or division or span
8544 * @param date Date - the new date
8546 _setDateDatepicker: function(target, date) {
8547 var inst = this._getInst(target);
8549 this._setDate(inst, date);
8550 this._updateDatepicker(inst);
8551 this._updateAlternate(inst);
8555 /* Get the date(s) for the first entry in a jQuery selection.
8556 * @param target element - the target input field or division or span
8557 * @param noDefault boolean - true if no default date is to be used
8558 * @return Date - the current date
8560 _getDateDatepicker: function(target, noDefault) {
8561 var inst = this._getInst(target);
8562 if (inst && !inst.inline) {
8563 this._setDateFromField(inst, noDefault);
8565 return (inst ? this._getDate(inst) : null);
8568 /* Handle keystrokes. */
8569 _doKeyDown: function(event) {
8570 var onSelect, dateStr, sel,
8571 inst = $.datepicker._getInst(event.target),
8573 isRTL = inst.dpDiv.is(".ui-datepicker-rtl");
8575 inst._keyEvent = true;
8576 if ($.datepicker._datepickerShowing) {
8577 switch (event.keyCode) {
8578 case 9: $.datepicker._hideDatepicker();
8580 break; // hide on tab out
8581 case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." +
8582 $.datepicker._currentClass + ")", inst.dpDiv);
8584 $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
8587 onSelect = $.datepicker._get(inst, "onSelect");
8589 dateStr = $.datepicker._formatDate(inst);
8591 // trigger custom callback
8592 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);
8594 $.datepicker._hideDatepicker();
8597 return false; // don't submit the form
8598 case 27: $.datepicker._hideDatepicker();
8599 break; // hide on escape
8600 case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
8601 -$.datepicker._get(inst, "stepBigMonths") :
8602 -$.datepicker._get(inst, "stepMonths")), "M");
8603 break; // previous month/year on page up/+ ctrl
8604 case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
8605 +$.datepicker._get(inst, "stepBigMonths") :
8606 +$.datepicker._get(inst, "stepMonths")), "M");
8607 break; // next month/year on page down/+ ctrl
8608 case 35: if (event.ctrlKey || event.metaKey) {
8609 $.datepicker._clearDate(event.target);
8611 handled = event.ctrlKey || event.metaKey;
8612 break; // clear on ctrl or command +end
8613 case 36: if (event.ctrlKey || event.metaKey) {
8614 $.datepicker._gotoToday(event.target);
8616 handled = event.ctrlKey || event.metaKey;
8617 break; // current on ctrl or command +home
8618 case 37: if (event.ctrlKey || event.metaKey) {
8619 $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D");
8621 handled = event.ctrlKey || event.metaKey;
8622 // -1 day on ctrl or command +left
8623 if (event.originalEvent.altKey) {
8624 $.datepicker._adjustDate(event.target, (event.ctrlKey ?
8625 -$.datepicker._get(inst, "stepBigMonths") :
8626 -$.datepicker._get(inst, "stepMonths")), "M");
8628 // next month/year on alt +left on Mac
8630 case 38: if (event.ctrlKey || event.metaKey) {
8631 $.datepicker._adjustDate(event.target, -7, "D");
8633 handled = event.ctrlKey || event.metaKey;
8634 break; // -1 week on ctrl or command +up
8635 case 39: if (event.ctrlKey || event.metaKey) {
8636 $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D");
8638 handled = event.ctrlKey || event.metaKey;
8639 // +1 day on ctrl or command +right
8640 if (event.originalEvent.altKey) {
8641 $.datepicker._adjustDate(event.target, (event.ctrlKey ?
8642 +$.datepicker._get(inst, "stepBigMonths") :
8643 +$.datepicker._get(inst, "stepMonths")), "M");
8645 // next month/year on alt +right
8647 case 40: if (event.ctrlKey || event.metaKey) {
8648 $.datepicker._adjustDate(event.target, +7, "D");
8650 handled = event.ctrlKey || event.metaKey;
8651 break; // +1 week on ctrl or command +down
8652 default: handled = false;
8654 } else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home
8655 $.datepicker._showDatepicker(this);
8661 event.preventDefault();
8662 event.stopPropagation();
8666 /* Filter entered characters - based on date format. */
8667 _doKeyPress: function(event) {
8669 inst = $.datepicker._getInst(event.target);
8671 if ($.datepicker._get(inst, "constrainInput")) {
8672 chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat"));
8673 chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode);
8674 return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1);
8678 /* Synchronise manual entry and field/alternate field. */
8679 _doKeyUp: function(event) {
8681 inst = $.datepicker._getInst(event.target);
8683 if (inst.input.val() !== inst.lastVal) {
8685 date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
8686 (inst.input ? inst.input.val() : null),
8687 $.datepicker._getFormatConfig(inst));
8689 if (date) { // only if valid
8690 $.datepicker._setDateFromField(inst);
8691 $.datepicker._updateAlternate(inst);
8692 $.datepicker._updateDatepicker(inst);
8701 /* Pop-up the date picker for a given input field.
8702 * If false returned from beforeShow event handler do not show.
8703 * @param input element - the input field attached to the date picker or
8704 * event - if triggered by focus
8706 _showDatepicker: function(input) {
8707 input = input.target || input;
8708 if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger
8709 input = $("input", input.parentNode)[0];
8712 if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here
8716 var inst, beforeShow, beforeShowSettings, isFixed,
8717 offset, showAnim, duration;
8719 inst = $.datepicker._getInst(input);
8720 if ($.datepicker._curInst && $.datepicker._curInst !== inst) {
8721 $.datepicker._curInst.dpDiv.stop(true, true);
8722 if ( inst && $.datepicker._datepickerShowing ) {
8723 $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );
8727 beforeShow = $.datepicker._get(inst, "beforeShow");
8728 beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
8729 if(beforeShowSettings === false){
8732 datepicker_extendRemove(inst.settings, beforeShowSettings);
8734 inst.lastVal = null;
8735 $.datepicker._lastInput = input;
8736 $.datepicker._setDateFromField(inst);
8738 if ($.datepicker._inDialog) { // hide cursor
8741 if (!$.datepicker._pos) { // position below input
8742 $.datepicker._pos = $.datepicker._findPos(input);
8743 $.datepicker._pos[1] += input.offsetHeight; // add the height
8747 $(input).parents().each(function() {
8748 isFixed |= $(this).css("position") === "fixed";
8752 offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
8753 $.datepicker._pos = null;
8754 //to avoid flashes on Firefox
8756 // determine sizing offscreen
8757 inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"});
8758 $.datepicker._updateDatepicker(inst);
8759 // fix width for dynamic number of date pickers
8760 // and adjust position before showing
8761 offset = $.datepicker._checkOffset(inst, offset, isFixed);
8762 inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
8763 "static" : (isFixed ? "fixed" : "absolute")), display: "none",
8764 left: offset.left + "px", top: offset.top + "px"});
8767 showAnim = $.datepicker._get(inst, "showAnim");
8768 duration = $.datepicker._get(inst, "duration");
8769 inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 );
8770 $.datepicker._datepickerShowing = true;
8772 if ( $.effects && $.effects.effect[ showAnim ] ) {
8773 inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration);
8775 inst.dpDiv[showAnim || "show"](showAnim ? duration : null);
8778 if ( $.datepicker._shouldFocusInput( inst ) ) {
8782 $.datepicker._curInst = inst;
8786 /* Generate the date picker content. */
8787 _updateDatepicker: function(inst) {
8788 this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
8789 datepicker_instActive = inst; // for delegate hover events
8790 inst.dpDiv.empty().append(this._generateHTML(inst));
8791 this._attachHandlers(inst);
8794 numMonths = this._getNumberOfMonths(inst),
8795 cols = numMonths[1],
8797 activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" );
8799 if ( activeCell.length > 0 ) {
8800 datepicker_handleMouseover.apply( activeCell.get( 0 ) );
8803 inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");
8805 inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em");
8807 inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") +
8808 "Class"]("ui-datepicker-multi");
8809 inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") +
8810 "Class"]("ui-datepicker-rtl");
8812 if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
8816 // deffered render of the years select (to avoid flashes on Firefox)
8817 if( inst.yearshtml ){
8818 origyearshtml = inst.yearshtml;
8819 setTimeout(function(){
8820 //assure that inst.yearshtml didn't change.
8821 if( origyearshtml === inst.yearshtml && inst.yearshtml ){
8822 inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml);
8824 origyearshtml = inst.yearshtml = null;
8829 // #6694 - don't focus the input if it's already focused
8830 // this breaks the change event in IE
8831 // Support: IE and jQuery <1.9
8832 _shouldFocusInput: function( inst ) {
8833 return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
8836 /* Check positioning to remain on screen. */
8837 _checkOffset: function(inst, offset, isFixed) {
8838 var dpWidth = inst.dpDiv.outerWidth(),
8839 dpHeight = inst.dpDiv.outerHeight(),
8840 inputWidth = inst.input ? inst.input.outerWidth() : 0,
8841 inputHeight = inst.input ? inst.input.outerHeight() : 0,
8842 viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()),
8843 viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop());
8845 offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0);
8846 offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0;
8847 offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
8849 // now check if datepicker is showing outside window viewport - move to a better place if so.
8850 offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
8851 Math.abs(offset.left + dpWidth - viewWidth) : 0);
8852 offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
8853 Math.abs(dpHeight + inputHeight) : 0);
8858 /* Find an object's position on the screen. */
8859 _findPos: function(obj) {
8861 inst = this._getInst(obj),
8862 isRTL = this._get(inst, "isRTL");
8864 while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) {
8865 obj = obj[isRTL ? "previousSibling" : "nextSibling"];
8868 position = $(obj).offset();
8869 return [position.left, position.top];
8872 /* Hide the date picker from view.
8873 * @param input element - the input field attached to the date picker
8875 _hideDatepicker: function(input) {
8876 var showAnim, duration, postProcess, onClose,
8877 inst = this._curInst;
8879 if (!inst || (input && inst !== $.data(input, "datepicker"))) {
8883 if (this._datepickerShowing) {
8884 showAnim = this._get(inst, "showAnim");
8885 duration = this._get(inst, "duration");
8886 postProcess = function() {
8887 $.datepicker._tidyDialog(inst);
8890 // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
8891 if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
8892 inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess);
8894 inst.dpDiv[(showAnim === "slideDown" ? "slideUp" :
8895 (showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess);
8901 this._datepickerShowing = false;
8903 onClose = this._get(inst, "onClose");
8905 onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]);
8908 this._lastInput = null;
8909 if (this._inDialog) {
8910 this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" });
8913 $("body").append(this.dpDiv);
8916 this._inDialog = false;
8920 /* Tidy up after a dialog display. */
8921 _tidyDialog: function(inst) {
8922 inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar");
8925 /* Close date picker if clicked elsewhere. */
8926 _checkExternalClick: function(event) {
8927 if (!$.datepicker._curInst) {
8931 var $target = $(event.target),
8932 inst = $.datepicker._getInst($target[0]);
8934 if ( ( ( $target[0].id !== $.datepicker._mainDivId &&
8935 $target.parents("#" + $.datepicker._mainDivId).length === 0 &&
8936 !$target.hasClass($.datepicker.markerClassName) &&
8937 !$target.closest("." + $.datepicker._triggerClass).length &&
8938 $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) ||
8939 ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) {
8940 $.datepicker._hideDatepicker();
8944 /* Adjust one of the date sub-fields. */
8945 _adjustDate: function(id, offset, period) {
8947 inst = this._getInst(target[0]);
8949 if (this._isDisabledDatepicker(target[0])) {
8952 this._adjustInstDate(inst, offset +
8953 (period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning
8955 this._updateDatepicker(inst);
8958 /* Action for current link. */
8959 _gotoToday: function(id) {
8962 inst = this._getInst(target[0]);
8964 if (this._get(inst, "gotoCurrent") && inst.currentDay) {
8965 inst.selectedDay = inst.currentDay;
8966 inst.drawMonth = inst.selectedMonth = inst.currentMonth;
8967 inst.drawYear = inst.selectedYear = inst.currentYear;
8970 inst.selectedDay = date.getDate();
8971 inst.drawMonth = inst.selectedMonth = date.getMonth();
8972 inst.drawYear = inst.selectedYear = date.getFullYear();
8974 this._notifyChange(inst);
8975 this._adjustDate(target);
8978 /* Action for selecting a new month/year. */
8979 _selectMonthYear: function(id, select, period) {
8981 inst = this._getInst(target[0]);
8983 inst["selected" + (period === "M" ? "Month" : "Year")] =
8984 inst["draw" + (period === "M" ? "Month" : "Year")] =
8985 parseInt(select.options[select.selectedIndex].value,10);
8987 this._notifyChange(inst);
8988 this._adjustDate(target);
8991 /* Action for selecting a day. */
8992 _selectDay: function(id, month, year, td) {
8996 if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
9000 inst = this._getInst(target[0]);
9001 inst.selectedDay = inst.currentDay = $("a", td).html();
9002 inst.selectedMonth = inst.currentMonth = month;
9003 inst.selectedYear = inst.currentYear = year;
9004 this._selectDate(id, this._formatDate(inst,
9005 inst.currentDay, inst.currentMonth, inst.currentYear));
9008 /* Erase the input field and hide the date picker. */
9009 _clearDate: function(id) {
9011 this._selectDate(target, "");
9014 /* Update the input field with the selected date. */
9015 _selectDate: function(id, dateStr) {
9018 inst = this._getInst(target[0]);
9020 dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
9022 inst.input.val(dateStr);
9024 this._updateAlternate(inst);
9026 onSelect = this._get(inst, "onSelect");
9028 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
9029 } else if (inst.input) {
9030 inst.input.trigger("change"); // fire the change event
9034 this._updateDatepicker(inst);
9036 this._hideDatepicker();
9037 this._lastInput = inst.input[0];
9038 if (typeof(inst.input[0]) !== "object") {
9039 inst.input.focus(); // restore focus
9041 this._lastInput = null;
9045 /* Update any alternate field to synchronise with the main field. */
9046 _updateAlternate: function(inst) {
9047 var altFormat, date, dateStr,
9048 altField = this._get(inst, "altField");
9050 if (altField) { // update alternate field too
9051 altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat");
9052 date = this._getDate(inst);
9053 dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
9054 $(altField).each(function() { $(this).val(dateStr); });
9058 /* Set as beforeShowDay function to prevent selection of weekends.
9059 * @param date Date - the date to customise
9060 * @return [boolean, string] - is this date selectable?, what is its CSS class?
9062 noWeekends: function(date) {
9063 var day = date.getDay();
9064 return [(day > 0 && day < 6), ""];
9067 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
9068 * @param date Date - the date to get the week for
9069 * @return number - the number of the week within the year that contains this date
9071 iso8601Week: function(date) {
9073 checkDate = new Date(date.getTime());
9075 // Find Thursday of this week starting on Monday
9076 checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
9078 time = checkDate.getTime();
9079 checkDate.setMonth(0); // Compare with Jan 1
9080 checkDate.setDate(1);
9081 return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
9084 /* Parse a string value into a date object.
9085 * See formatDate below for the possible formats.
9087 * @param format string - the expected format of the date
9088 * @param value string - the date in the above format
9089 * @param settings Object - attributes include:
9090 * shortYearCutoff number - the cutoff year for determining the century (optional)
9091 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
9092 * dayNames string[7] - names of the days from Sunday (optional)
9093 * monthNamesShort string[12] - abbreviated names of the months (optional)
9094 * monthNames string[12] - names of the months (optional)
9095 * @return Date - the extracted date value or null if value is blank
9097 parseDate: function (format, value, settings) {
9098 if (format == null || value == null) {
9099 throw "Invalid arguments";
9102 value = (typeof value === "object" ? value.toString() : value + "");
9107 var iFormat, dim, extra,
9109 shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff,
9110 shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
9111 new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)),
9112 dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
9113 dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
9114 monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
9115 monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
9122 // Check whether a format character is doubled
9123 lookAhead = function(match) {
9124 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
9130 // Extract a number from the string value
9131 getNumber = function(match) {
9132 var isDoubled = lookAhead(match),
9133 size = (match === "@" ? 14 : (match === "!" ? 20 :
9134 (match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))),
9135 minSize = (match === "y" ? size : 1),
9136 digits = new RegExp("^\\d{" + minSize + "," + size + "}"),
9137 num = value.substring(iValue).match(digits);
9139 throw "Missing number at position " + iValue;
9141 iValue += num[0].length;
9142 return parseInt(num[0], 10);
9144 // Extract a name from the string value and convert to an index
9145 getName = function(match, shortNames, longNames) {
9147 names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {
9149 }).sort(function (a, b) {
9150 return -(a[1].length - b[1].length);
9153 $.each(names, function (i, pair) {
9155 if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) {
9157 iValue += name.length;
9164 throw "Unknown name at position " + iValue;
9167 // Confirm that a literal character matches the string value
9168 checkLiteral = function() {
9169 if (value.charAt(iValue) !== format.charAt(iFormat)) {
9170 throw "Unexpected literal at position " + iValue;
9175 for (iFormat = 0; iFormat < format.length; iFormat++) {
9177 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
9183 switch (format.charAt(iFormat)) {
9185 day = getNumber("d");
9188 getName("D", dayNamesShort, dayNames);
9191 doy = getNumber("o");
9194 month = getNumber("m");
9197 month = getName("M", monthNamesShort, monthNames);
9200 year = getNumber("y");
9203 date = new Date(getNumber("@"));
9204 year = date.getFullYear();
9205 month = date.getMonth() + 1;
9206 day = date.getDate();
9209 date = new Date((getNumber("!") - this._ticksTo1970) / 10000);
9210 year = date.getFullYear();
9211 month = date.getMonth() + 1;
9212 day = date.getDate();
9215 if (lookAhead("'")){
9227 if (iValue < value.length){
9228 extra = value.substr(iValue);
9229 if (!/^\s+/.test(extra)) {
9230 throw "Extra/unparsed characters found in date: " + extra;
9235 year = new Date().getFullYear();
9236 } else if (year < 100) {
9237 year += new Date().getFullYear() - new Date().getFullYear() % 100 +
9238 (year <= shortYearCutoff ? 0 : -100);
9245 dim = this._getDaysInMonth(year, month - 1);
9254 date = this._daylightSavingAdjust(new Date(year, month - 1, day));
9255 if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) {
9256 throw "Invalid date"; // E.g. 31/02/00
9261 /* Standard date formats. */
9262 ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
9263 COOKIE: "D, dd M yy",
9264 ISO_8601: "yy-mm-dd",
9265 RFC_822: "D, d M y",
9266 RFC_850: "DD, dd-M-y",
9267 RFC_1036: "D, d M y",
9268 RFC_1123: "D, d M yy",
9269 RFC_2822: "D, d M yy",
9270 RSS: "D, d M y", // RFC 822
9273 W3C: "yy-mm-dd", // ISO 8601
9275 _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
9276 Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
9278 /* Format a date object into a string value.
9279 * The format can be combinations of the following:
9280 * d - day of month (no leading zero)
9281 * dd - day of month (two digit)
9282 * o - day of year (no leading zeros)
9283 * oo - day of year (three digit)
9284 * D - day name short
9285 * DD - day name long
9286 * m - month of year (no leading zero)
9287 * mm - month of year (two digit)
9288 * M - month name short
9289 * MM - month name long
9290 * y - year (two digit)
9291 * yy - year (four digit)
9292 * @ - Unix timestamp (ms since 01/01/1970)
9293 * ! - Windows ticks (100ns since 01/01/0001)
9294 * "..." - literal text
9297 * @param format string - the desired format of the date
9298 * @param date Date - the date value to format
9299 * @param settings Object - attributes include:
9300 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
9301 * dayNames string[7] - names of the days from Sunday (optional)
9302 * monthNamesShort string[12] - abbreviated names of the months (optional)
9303 * monthNames string[12] - names of the months (optional)
9304 * @return string - the date in the above format
9306 formatDate: function (format, date, settings) {
9312 dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
9313 dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
9314 monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
9315 monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
9316 // Check whether a format character is doubled
9317 lookAhead = function(match) {
9318 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
9324 // Format a number, with leading zero if necessary
9325 formatNumber = function(match, value, len) {
9326 var num = "" + value;
9327 if (lookAhead(match)) {
9328 while (num.length < len) {
9334 // Format a name, short or long as requested
9335 formatName = function(match, value, shortNames, longNames) {
9336 return (lookAhead(match) ? longNames[value] : shortNames[value]);
9342 for (iFormat = 0; iFormat < format.length; iFormat++) {
9344 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
9347 output += format.charAt(iFormat);
9350 switch (format.charAt(iFormat)) {
9352 output += formatNumber("d", date.getDate(), 2);
9355 output += formatName("D", date.getDay(), dayNamesShort, dayNames);
9358 output += formatNumber("o",
9359 Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);
9362 output += formatNumber("m", date.getMonth() + 1, 2);
9365 output += formatName("M", date.getMonth(), monthNamesShort, monthNames);
9368 output += (lookAhead("y") ? date.getFullYear() :
9369 (date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100);
9372 output += date.getTime();
9375 output += date.getTime() * 10000 + this._ticksTo1970;
9378 if (lookAhead("'")) {
9385 output += format.charAt(iFormat);
9393 /* Extract all possible characters from the date format. */
9394 _possibleChars: function (format) {
9398 // Check whether a format character is doubled
9399 lookAhead = function(match) {
9400 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
9407 for (iFormat = 0; iFormat < format.length; iFormat++) {
9409 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
9412 chars += format.charAt(iFormat);
9415 switch (format.charAt(iFormat)) {
9416 case "d": case "m": case "y": case "@":
9417 chars += "0123456789";
9420 return null; // Accept anything
9422 if (lookAhead("'")) {
9429 chars += format.charAt(iFormat);
9436 /* Get a setting value, defaulting if necessary. */
9437 _get: function(inst, name) {
9438 return inst.settings[name] !== undefined ?
9439 inst.settings[name] : this._defaults[name];
9442 /* Parse existing date and initialise date picker. */
9443 _setDateFromField: function(inst, noDefault) {
9444 if (inst.input.val() === inst.lastVal) {
9448 var dateFormat = this._get(inst, "dateFormat"),
9449 dates = inst.lastVal = inst.input ? inst.input.val() : null,
9450 defaultDate = this._getDefaultDate(inst),
9452 settings = this._getFormatConfig(inst);
9455 date = this.parseDate(dateFormat, dates, settings) || defaultDate;
9457 dates = (noDefault ? "" : dates);
9459 inst.selectedDay = date.getDate();
9460 inst.drawMonth = inst.selectedMonth = date.getMonth();
9461 inst.drawYear = inst.selectedYear = date.getFullYear();
9462 inst.currentDay = (dates ? date.getDate() : 0);
9463 inst.currentMonth = (dates ? date.getMonth() : 0);
9464 inst.currentYear = (dates ? date.getFullYear() : 0);
9465 this._adjustInstDate(inst);
9468 /* Retrieve the default date shown on opening. */
9469 _getDefaultDate: function(inst) {
9470 return this._restrictMinMax(inst,
9471 this._determineDate(inst, this._get(inst, "defaultDate"), new Date()));
9474 /* A date may be specified as an exact value or a relative one. */
9475 _determineDate: function(inst, date, defaultDate) {
9476 var offsetNumeric = function(offset) {
9477 var date = new Date();
9478 date.setDate(date.getDate() + offset);
9481 offsetString = function(offset) {
9483 return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
9484 offset, $.datepicker._getFormatConfig(inst));
9490 var date = (offset.toLowerCase().match(/^c/) ?
9491 $.datepicker._getDate(inst) : null) || new Date(),
9492 year = date.getFullYear(),
9493 month = date.getMonth(),
9494 day = date.getDate(),
9495 pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
9496 matches = pattern.exec(offset);
9499 switch (matches[2] || "d") {
9500 case "d" : case "D" :
9501 day += parseInt(matches[1],10); break;
9502 case "w" : case "W" :
9503 day += parseInt(matches[1],10) * 7; break;
9504 case "m" : case "M" :
9505 month += parseInt(matches[1],10);
9506 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
9508 case "y": case "Y" :
9509 year += parseInt(matches[1],10);
9510 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
9513 matches = pattern.exec(offset);
9515 return new Date(year, month, day);
9517 newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) :
9518 (typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));
9520 newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate);
9522 newDate.setHours(0);
9523 newDate.setMinutes(0);
9524 newDate.setSeconds(0);
9525 newDate.setMilliseconds(0);
9527 return this._daylightSavingAdjust(newDate);
9530 /* Handle switch to/from daylight saving.
9531 * Hours may be non-zero on daylight saving cut-over:
9532 * > 12 when midnight changeover, but then cannot generate
9533 * midnight datetime, so jump to 1AM, otherwise reset.
9534 * @param date (Date) the date to check
9535 * @return (Date) the corrected date
9537 _daylightSavingAdjust: function(date) {
9541 date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
9545 /* Set the date(s) directly. */
9546 _setDate: function(inst, date, noChange) {
9548 origMonth = inst.selectedMonth,
9549 origYear = inst.selectedYear,
9550 newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
9552 inst.selectedDay = inst.currentDay = newDate.getDate();
9553 inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
9554 inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
9555 if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) {
9556 this._notifyChange(inst);
9558 this._adjustInstDate(inst);
9560 inst.input.val(clear ? "" : this._formatDate(inst));
9564 /* Retrieve the date(s) directly. */
9565 _getDate: function(inst) {
9566 var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null :
9567 this._daylightSavingAdjust(new Date(
9568 inst.currentYear, inst.currentMonth, inst.currentDay)));
9572 /* Attach the onxxx handlers. These are declared statically so
9573 * they work with static code transformers like Caja.
9575 _attachHandlers: function(inst) {
9576 var stepMonths = this._get(inst, "stepMonths"),
9577 id = "#" + inst.id.replace( /\\\\/g, "\\" );
9578 inst.dpDiv.find("[data-handler]").map(function () {
9581 $.datepicker._adjustDate(id, -stepMonths, "M");
9584 $.datepicker._adjustDate(id, +stepMonths, "M");
9587 $.datepicker._hideDatepicker();
9589 today: function () {
9590 $.datepicker._gotoToday(id);
9592 selectDay: function () {
9593 $.datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this);
9596 selectMonth: function () {
9597 $.datepicker._selectMonthYear(id, this, "M");
9600 selectYear: function () {
9601 $.datepicker._selectMonthYear(id, this, "Y");
9605 $(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]);
9609 /* Generate the HTML for the current state of the date picker. */
9610 _generateHTML: function(inst) {
9611 var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
9612 controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
9613 monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
9614 selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
9615 cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
9616 printDate, dRow, tbody, daySettings, otherMonth, unselectable,
9617 tempDate = new Date(),
9618 today = this._daylightSavingAdjust(
9619 new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time
9620 isRTL = this._get(inst, "isRTL"),
9621 showButtonPanel = this._get(inst, "showButtonPanel"),
9622 hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"),
9623 navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"),
9624 numMonths = this._getNumberOfMonths(inst),
9625 showCurrentAtPos = this._get(inst, "showCurrentAtPos"),
9626 stepMonths = this._get(inst, "stepMonths"),
9627 isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1),
9628 currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
9629 new Date(inst.currentYear, inst.currentMonth, inst.currentDay))),
9630 minDate = this._getMinMaxDate(inst, "min"),
9631 maxDate = this._getMinMaxDate(inst, "max"),
9632 drawMonth = inst.drawMonth - showCurrentAtPos,
9633 drawYear = inst.drawYear;
9635 if (drawMonth < 0) {
9640 maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
9641 maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
9642 maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
9643 while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
9645 if (drawMonth < 0) {
9651 inst.drawMonth = drawMonth;
9652 inst.drawYear = drawYear;
9654 prevText = this._get(inst, "prevText");
9655 prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
9656 this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
9657 this._getFormatConfig(inst)));
9659 prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
9660 "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
9661 " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" :
9662 (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>"));
9664 nextText = this._get(inst, "nextText");
9665 nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
9666 this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
9667 this._getFormatConfig(inst)));
9669 next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
9670 "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
9671 " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" :
9672 (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>"));
9674 currentText = this._get(inst, "currentText");
9675 gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today);
9676 currentText = (!navigationAsDateFormat ? currentText :
9677 this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
9679 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'>" +
9680 this._get(inst, "closeText") + "</button>" : "");
9682 buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") +
9683 (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'" +
9684 ">" + currentText + "</button>" : "") + (isRTL ? "" : controls) + "</div>" : "";
9686 firstDay = parseInt(this._get(inst, "firstDay"),10);
9687 firstDay = (isNaN(firstDay) ? 0 : firstDay);
9689 showWeek = this._get(inst, "showWeek");
9690 dayNames = this._get(inst, "dayNames");
9691 dayNamesMin = this._get(inst, "dayNamesMin");
9692 monthNames = this._get(inst, "monthNames");
9693 monthNamesShort = this._get(inst, "monthNamesShort");
9694 beforeShowDay = this._get(inst, "beforeShowDay");
9695 showOtherMonths = this._get(inst, "showOtherMonths");
9696 selectOtherMonths = this._get(inst, "selectOtherMonths");
9697 defaultDate = this._getDefaultDate(inst);
9700 for (row = 0; row < numMonths[0]; row++) {
9703 for (col = 0; col < numMonths[1]; col++) {
9704 selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
9705 cornerClass = " ui-corner-all";
9708 calender += "<div class='ui-datepicker-group";
9709 if (numMonths[1] > 1) {
9711 case 0: calender += " ui-datepicker-group-first";
9712 cornerClass = " ui-corner-" + (isRTL ? "right" : "left"); break;
9713 case numMonths[1]-1: calender += " ui-datepicker-group-last";
9714 cornerClass = " ui-corner-" + (isRTL ? "left" : "right"); break;
9715 default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
9720 calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
9721 (/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") +
9722 (/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") +
9723 this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
9724 row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
9725 "</div><table class='ui-datepicker-calendar'><thead>" +
9727 thead = (showWeek ? "<th class='ui-datepicker-week-col'>" + this._get(inst, "weekHeader") + "</th>" : "");
9728 for (dow = 0; dow < 7; dow++) { // days of the week
9729 day = (dow + firstDay) % 7;
9730 thead += "<th scope='col'" + ((dow + firstDay + 6) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "") + ">" +
9731 "<span title='" + dayNames[day] + "'>" + dayNamesMin[day] + "</span></th>";
9733 calender += thead + "</tr></thead><tbody>";
9734 daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
9735 if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) {
9736 inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
9738 leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
9739 curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate
9740 numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043)
9741 this.maxRows = numRows;
9742 printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
9743 for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows
9745 tbody = (!showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
9746 this._get(inst, "calculateWeek")(printDate) + "</td>");
9747 for (dow = 0; dow < 7; dow++) { // create date picker days
9748 daySettings = (beforeShowDay ?
9749 beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]);
9750 otherMonth = (printDate.getMonth() !== drawMonth);
9751 unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
9752 (minDate && printDate < minDate) || (maxDate && printDate > maxDate);
9753 tbody += "<td class='" +
9754 ((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends
9755 (otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months
9756 ((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key
9757 (defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ?
9758 // or defaultDate is current printedDate and defaultDate is selectedDate
9759 " " + this._dayOverClass : "") + // highlight selected day
9760 (unselectable ? " " + this._unselectableClass + " ui-state-disabled": "") + // highlight unselectable days
9761 (otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates
9762 (printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day
9763 (printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different)
9764 ((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "'") + "'" : "") + // cell title
9765 (unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions
9766 (otherMonth && !showOtherMonths ? " " : // display for other months
9767 (unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
9768 (printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") +
9769 (printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day
9770 (otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months
9771 "' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date
9772 printDate.setDate(printDate.getDate() + 1);
9773 printDate = this._daylightSavingAdjust(printDate);
9775 calender += tbody + "</tr>";
9778 if (drawMonth > 11) {
9782 calender += "</tbody></table>" + (isMultiMonth ? "</div>" +
9783 ((numMonths[0] > 0 && col === numMonths[1]-1) ? "<div class='ui-datepicker-row-break'></div>" : "") : "");
9788 html += buttonPanel;
9789 inst._keyEvent = false;
9793 /* Generate the month and year header. */
9794 _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
9795 secondary, monthNames, monthNamesShort) {
9797 var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
9798 changeMonth = this._get(inst, "changeMonth"),
9799 changeYear = this._get(inst, "changeYear"),
9800 showMonthAfterYear = this._get(inst, "showMonthAfterYear"),
9801 html = "<div class='ui-datepicker-title'>",
9805 if (secondary || !changeMonth) {
9806 monthHtml += "<span class='ui-datepicker-month'>" + monthNames[drawMonth] + "</span>";
9808 inMinYear = (minDate && minDate.getFullYear() === drawYear);
9809 inMaxYear = (maxDate && maxDate.getFullYear() === drawYear);
9810 monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
9811 for ( month = 0; month < 12; month++) {
9812 if ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) {
9813 monthHtml += "<option value='" + month + "'" +
9814 (month === drawMonth ? " selected='selected'" : "") +
9815 ">" + monthNamesShort[month] + "</option>";
9818 monthHtml += "</select>";
9821 if (!showMonthAfterYear) {
9822 html += monthHtml + (secondary || !(changeMonth && changeYear) ? " " : "");
9826 if ( !inst.yearshtml ) {
9827 inst.yearshtml = "";
9828 if (secondary || !changeYear) {
9829 html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
9831 // determine range of years to display
9832 years = this._get(inst, "yearRange").split(":");
9833 thisYear = new Date().getFullYear();
9834 determineYear = function(value) {
9835 var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) :
9836 (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) :
9837 parseInt(value, 10)));
9838 return (isNaN(year) ? thisYear : year);
9840 year = determineYear(years[0]);
9841 endYear = Math.max(year, determineYear(years[1] || ""));
9842 year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
9843 endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
9844 inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
9845 for (; year <= endYear; year++) {
9846 inst.yearshtml += "<option value='" + year + "'" +
9847 (year === drawYear ? " selected='selected'" : "") +
9848 ">" + year + "</option>";
9850 inst.yearshtml += "</select>";
9852 html += inst.yearshtml;
9853 inst.yearshtml = null;
9857 html += this._get(inst, "yearSuffix");
9858 if (showMonthAfterYear) {
9859 html += (secondary || !(changeMonth && changeYear) ? " " : "") + monthHtml;
9861 html += "</div>"; // Close datepicker_header
9865 /* Adjust one of the date sub-fields. */
9866 _adjustInstDate: function(inst, offset, period) {
9867 var year = inst.drawYear + (period === "Y" ? offset : 0),
9868 month = inst.drawMonth + (period === "M" ? offset : 0),
9869 day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0),
9870 date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day)));
9872 inst.selectedDay = date.getDate();
9873 inst.drawMonth = inst.selectedMonth = date.getMonth();
9874 inst.drawYear = inst.selectedYear = date.getFullYear();
9875 if (period === "M" || period === "Y") {
9876 this._notifyChange(inst);
9880 /* Ensure a date is within any min/max bounds. */
9881 _restrictMinMax: function(inst, date) {
9882 var minDate = this._getMinMaxDate(inst, "min"),
9883 maxDate = this._getMinMaxDate(inst, "max"),
9884 newDate = (minDate && date < minDate ? minDate : date);
9885 return (maxDate && newDate > maxDate ? maxDate : newDate);
9888 /* Notify change of month/year. */
9889 _notifyChange: function(inst) {
9890 var onChange = this._get(inst, "onChangeMonthYear");
9892 onChange.apply((inst.input ? inst.input[0] : null),
9893 [inst.selectedYear, inst.selectedMonth + 1, inst]);
9897 /* Determine the number of months to show. */
9898 _getNumberOfMonths: function(inst) {
9899 var numMonths = this._get(inst, "numberOfMonths");
9900 return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths));
9903 /* Determine the current maximum date - ensure no time components are set. */
9904 _getMinMaxDate: function(inst, minMax) {
9905 return this._determineDate(inst, this._get(inst, minMax + "Date"), null);
9908 /* Find the number of days in a given month. */
9909 _getDaysInMonth: function(year, month) {
9910 return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();
9913 /* Find the day of the week of the first of a month. */
9914 _getFirstDayOfMonth: function(year, month) {
9915 return new Date(year, month, 1).getDay();
9918 /* Determines if we should allow a "next/prev" month display change. */
9919 _canAdjustMonth: function(inst, offset, curYear, curMonth) {
9920 var numMonths = this._getNumberOfMonths(inst),
9921 date = this._daylightSavingAdjust(new Date(curYear,
9922 curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
9925 date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
9927 return this._isInRange(inst, date);
9930 /* Is the given date in the accepted range? */
9931 _isInRange: function(inst, date) {
9932 var yearSplit, currentYear,
9933 minDate = this._getMinMaxDate(inst, "min"),
9934 maxDate = this._getMinMaxDate(inst, "max"),
9937 years = this._get(inst, "yearRange");
9939 yearSplit = years.split(":");
9940 currentYear = new Date().getFullYear();
9941 minYear = parseInt(yearSplit[0], 10);
9942 maxYear = parseInt(yearSplit[1], 10);
9943 if ( yearSplit[0].match(/[+\-].*/) ) {
9944 minYear += currentYear;
9946 if ( yearSplit[1].match(/[+\-].*/) ) {
9947 maxYear += currentYear;
9951 return ((!minDate || date.getTime() >= minDate.getTime()) &&
9952 (!maxDate || date.getTime() <= maxDate.getTime()) &&
9953 (!minYear || date.getFullYear() >= minYear) &&
9954 (!maxYear || date.getFullYear() <= maxYear));
9957 /* Provide the configuration settings for formatting/parsing. */
9958 _getFormatConfig: function(inst) {
9959 var shortYearCutoff = this._get(inst, "shortYearCutoff");
9960 shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff :
9961 new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
9962 return {shortYearCutoff: shortYearCutoff,
9963 dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"),
9964 monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")};
9967 /* Format the given date for display. */
9968 _formatDate: function(inst, day, month, year) {
9970 inst.currentDay = inst.selectedDay;
9971 inst.currentMonth = inst.selectedMonth;
9972 inst.currentYear = inst.selectedYear;
9974 var date = (day ? (typeof day === "object" ? day :
9975 this._daylightSavingAdjust(new Date(year, month, day))) :
9976 this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
9977 return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst));
9982 * Bind hover events for datepicker elements.
9983 * Done via delegate so the binding only occurs once in the lifetime of the parent div.
9984 * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
9986 function datepicker_bindHover(dpDiv) {
9987 var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
9988 return dpDiv.delegate(selector, "mouseout", function() {
9989 $(this).removeClass("ui-state-hover");
9990 if (this.className.indexOf("ui-datepicker-prev") !== -1) {
9991 $(this).removeClass("ui-datepicker-prev-hover");
9993 if (this.className.indexOf("ui-datepicker-next") !== -1) {
9994 $(this).removeClass("ui-datepicker-next-hover");
9997 .delegate( selector, "mouseover", datepicker_handleMouseover );
10000 function datepicker_handleMouseover() {
10001 if (!$.datepicker._isDisabledDatepicker( datepicker_instActive.inline? datepicker_instActive.dpDiv.parent()[0] : datepicker_instActive.input[0])) {
10002 $(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");
10003 $(this).addClass("ui-state-hover");
10004 if (this.className.indexOf("ui-datepicker-prev") !== -1) {
10005 $(this).addClass("ui-datepicker-prev-hover");
10007 if (this.className.indexOf("ui-datepicker-next") !== -1) {
10008 $(this).addClass("ui-datepicker-next-hover");
10013 /* jQuery extend now ignores nulls! */
10014 function datepicker_extendRemove(target, props) {
10015 $.extend(target, props);
10016 for (var name in props) {
10017 if (props[name] == null) {
10018 target[name] = props[name];
10024 /* Invoke the datepicker functionality.
10025 @param options string - a command, optionally followed by additional parameters or
10026 Object - settings for attaching new datepicker functionality
10027 @return jQuery object */
10028 $.fn.datepicker = function(options){
10030 /* Verify an empty collection wasn't passed - Fixes #6976 */
10031 if ( !this.length ) {
10035 /* Initialise the date picker. */
10036 if (!$.datepicker.initialized) {
10037 $(document).mousedown($.datepicker._checkExternalClick);
10038 $.datepicker.initialized = true;
10041 /* Append datepicker main container to body if not exist. */
10042 if ($("#"+$.datepicker._mainDivId).length === 0) {
10043 $("body").append($.datepicker.dpDiv);
10046 var otherArgs = Array.prototype.slice.call(arguments, 1);
10047 if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) {
10048 return $.datepicker["_" + options + "Datepicker"].
10049 apply($.datepicker, [this[0]].concat(otherArgs));
10051 if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") {
10052 return $.datepicker["_" + options + "Datepicker"].
10053 apply($.datepicker, [this[0]].concat(otherArgs));
10055 return this.each(function() {
10056 typeof options === "string" ?
10057 $.datepicker["_" + options + "Datepicker"].
10058 apply($.datepicker, [this].concat(otherArgs)) :
10059 $.datepicker._attachDatepicker(this, options);
10063 $.datepicker = new Datepicker(); // singleton instance
10064 $.datepicker.initialized = false;
10065 $.datepicker.uuid = new Date().getTime();
10066 $.datepicker.version = "1.11.3";
10068 var datepicker = $.datepicker;
10072 * jQuery UI Dialog 1.11.3
10073 * http://jqueryui.com
10075 * Copyright jQuery Foundation and other contributors
10076 * Released under the MIT license.
10077 * http://jquery.org/license
10079 * http://api.jqueryui.com/dialog/
10083 var dialog = $.widget( "ui.dialog", {
10089 closeOnEscape: true,
10090 closeText: "Close",
10105 // Ensure the titlebar is always visible
10106 using: function( pos ) {
10107 var topOffset = $( this ).css( pos ).offset().top;
10108 if ( topOffset < 0 ) {
10109 $( this ).css( "top", pos.top - topOffset );
10131 sizeRelatedOptions: {
10141 resizableRelatedOptions: {
10148 _create: function() {
10149 this.originalCss = {
10150 display: this.element[ 0 ].style.display,
10151 width: this.element[ 0 ].style.width,
10152 minHeight: this.element[ 0 ].style.minHeight,
10153 maxHeight: this.element[ 0 ].style.maxHeight,
10154 height: this.element[ 0 ].style.height
10156 this.originalPosition = {
10157 parent: this.element.parent(),
10158 index: this.element.parent().children().index( this.element )
10160 this.originalTitle = this.element.attr( "title" );
10161 this.options.title = this.options.title || this.originalTitle;
10163 this._createWrapper();
10167 .removeAttr( "title" )
10168 .addClass( "ui-dialog-content ui-widget-content" )
10169 .appendTo( this.uiDialog );
10171 this._createTitlebar();
10172 this._createButtonPane();
10174 if ( this.options.draggable && $.fn.draggable ) {
10175 this._makeDraggable();
10177 if ( this.options.resizable && $.fn.resizable ) {
10178 this._makeResizable();
10181 this._isOpen = false;
10183 this._trackFocus();
10186 _init: function() {
10187 if ( this.options.autoOpen ) {
10192 _appendTo: function() {
10193 var element = this.options.appendTo;
10194 if ( element && (element.jquery || element.nodeType) ) {
10195 return $( element );
10197 return this.document.find( element || "body" ).eq( 0 );
10200 _destroy: function() {
10202 originalPosition = this.originalPosition;
10204 this._destroyOverlay();
10208 .removeClass( "ui-dialog-content ui-widget-content" )
10209 .css( this.originalCss )
10210 // Without detaching first, the following becomes really slow
10213 this.uiDialog.stop( true, true ).remove();
10215 if ( this.originalTitle ) {
10216 this.element.attr( "title", this.originalTitle );
10219 next = originalPosition.parent.children().eq( originalPosition.index );
10220 // Don't try to place the dialog next to itself (#8613)
10221 if ( next.length && next[ 0 ] !== this.element[ 0 ] ) {
10222 next.before( this.element );
10224 originalPosition.parent.append( this.element );
10228 widget: function() {
10229 return this.uiDialog;
10235 close: function( event ) {
10239 if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) {
10243 this._isOpen = false;
10244 this._focusedElement = null;
10245 this._destroyOverlay();
10246 this._untrackInstance();
10248 if ( !this.opener.filter( ":focusable" ).focus().length ) {
10251 // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
10253 activeElement = this.document[ 0 ].activeElement;
10255 // Support: IE9, IE10
10256 // If the <body> is blurred, IE will switch windows, see #4520
10257 if ( activeElement && activeElement.nodeName.toLowerCase() !== "body" ) {
10259 // Hiding a focused element doesn't trigger blur in WebKit
10260 // so in case we have nothing to focus on, explicitly blur the active element
10261 // https://bugs.webkit.org/show_bug.cgi?id=47182
10262 $( activeElement ).blur();
10264 } catch ( error ) {}
10267 this._hide( this.uiDialog, this.options.hide, function() {
10268 that._trigger( "close", event );
10272 isOpen: function() {
10273 return this._isOpen;
10276 moveToTop: function() {
10280 _moveToTop: function( event, silent ) {
10282 zIndicies = this.uiDialog.siblings( ".ui-front:visible" ).map(function() {
10283 return +$( this ).css( "z-index" );
10285 zIndexMax = Math.max.apply( null, zIndicies );
10287 if ( zIndexMax >= +this.uiDialog.css( "z-index" ) ) {
10288 this.uiDialog.css( "z-index", zIndexMax + 1 );
10292 if ( moved && !silent ) {
10293 this._trigger( "focus", event );
10300 if ( this._isOpen ) {
10301 if ( this._moveToTop() ) {
10302 this._focusTabbable();
10307 this._isOpen = true;
10308 this.opener = $( this.document[ 0 ].activeElement );
10312 this._createOverlay();
10313 this._moveToTop( null, true );
10315 // Ensure the overlay is moved to the top with the dialog, but only when
10316 // opening. The overlay shouldn't move after the dialog is open so that
10317 // modeless dialogs opened after the modal dialog stack properly.
10318 if ( this.overlay ) {
10319 this.overlay.css( "z-index", this.uiDialog.css( "z-index" ) - 1 );
10322 this._show( this.uiDialog, this.options.show, function() {
10323 that._focusTabbable();
10324 that._trigger( "focus" );
10327 // Track the dialog immediately upon openening in case a focus event
10328 // somehow occurs outside of the dialog before an element inside the
10329 // dialog is focused (#10152)
10330 this._makeFocusTarget();
10332 this._trigger( "open" );
10335 _focusTabbable: function() {
10336 // Set focus to the first match:
10337 // 1. An element that was focused previously
10338 // 2. First element inside the dialog matching [autofocus]
10339 // 3. Tabbable element inside the content element
10340 // 4. Tabbable element inside the buttonpane
10341 // 5. The close button
10342 // 6. The dialog itself
10343 var hasFocus = this._focusedElement;
10345 hasFocus = this.element.find( "[autofocus]" );
10347 if ( !hasFocus.length ) {
10348 hasFocus = this.element.find( ":tabbable" );
10350 if ( !hasFocus.length ) {
10351 hasFocus = this.uiDialogButtonPane.find( ":tabbable" );
10353 if ( !hasFocus.length ) {
10354 hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" );
10356 if ( !hasFocus.length ) {
10357 hasFocus = this.uiDialog;
10359 hasFocus.eq( 0 ).focus();
10362 _keepFocus: function( event ) {
10363 function checkFocus() {
10364 var activeElement = this.document[0].activeElement,
10365 isActive = this.uiDialog[0] === activeElement ||
10366 $.contains( this.uiDialog[0], activeElement );
10368 this._focusTabbable();
10371 event.preventDefault();
10372 checkFocus.call( this );
10374 // IE <= 8 doesn't prevent moving focus even with event.preventDefault()
10375 // so we check again later
10376 this._delay( checkFocus );
10379 _createWrapper: function() {
10380 this.uiDialog = $("<div>")
10381 .addClass( "ui-dialog ui-widget ui-widget-content ui-corner-all ui-front " +
10382 this.options.dialogClass )
10385 // Setting tabIndex makes the div focusable
10389 .appendTo( this._appendTo() );
10391 this._on( this.uiDialog, {
10392 keydown: function( event ) {
10393 if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
10394 event.keyCode === $.ui.keyCode.ESCAPE ) {
10395 event.preventDefault();
10396 this.close( event );
10400 // prevent tabbing out of dialogs
10401 if ( event.keyCode !== $.ui.keyCode.TAB || event.isDefaultPrevented() ) {
10404 var tabbables = this.uiDialog.find( ":tabbable" ),
10405 first = tabbables.filter( ":first" ),
10406 last = tabbables.filter( ":last" );
10408 if ( ( event.target === last[0] || event.target === this.uiDialog[0] ) && !event.shiftKey ) {
10409 this._delay(function() {
10412 event.preventDefault();
10413 } else if ( ( event.target === first[0] || event.target === this.uiDialog[0] ) && event.shiftKey ) {
10414 this._delay(function() {
10417 event.preventDefault();
10420 mousedown: function( event ) {
10421 if ( this._moveToTop( event ) ) {
10422 this._focusTabbable();
10427 // We assume that any existing aria-describedby attribute means
10428 // that the dialog content is marked up properly
10429 // otherwise we brute force the content as the description
10430 if ( !this.element.find( "[aria-describedby]" ).length ) {
10431 this.uiDialog.attr({
10432 "aria-describedby": this.element.uniqueId().attr( "id" )
10437 _createTitlebar: function() {
10440 this.uiDialogTitlebar = $( "<div>" )
10441 .addClass( "ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix" )
10442 .prependTo( this.uiDialog );
10443 this._on( this.uiDialogTitlebar, {
10444 mousedown: function( event ) {
10445 // Don't prevent click on close button (#8838)
10446 // Focusing a dialog that is partially scrolled out of view
10447 // causes the browser to scroll it into view, preventing the click event
10448 if ( !$( event.target ).closest( ".ui-dialog-titlebar-close" ) ) {
10449 // Dialog isn't getting focus when dragging (#8063)
10450 this.uiDialog.focus();
10456 // Use type="button" to prevent enter keypresses in textboxes from closing the
10457 // dialog in IE (#9312)
10458 this.uiDialogTitlebarClose = $( "<button type='button'></button>" )
10460 label: this.options.closeText,
10462 primary: "ui-icon-closethick"
10466 .addClass( "ui-dialog-titlebar-close" )
10467 .appendTo( this.uiDialogTitlebar );
10468 this._on( this.uiDialogTitlebarClose, {
10469 click: function( event ) {
10470 event.preventDefault();
10471 this.close( event );
10475 uiDialogTitle = $( "<span>" )
10477 .addClass( "ui-dialog-title" )
10478 .prependTo( this.uiDialogTitlebar );
10479 this._title( uiDialogTitle );
10481 this.uiDialog.attr({
10482 "aria-labelledby": uiDialogTitle.attr( "id" )
10486 _title: function( title ) {
10487 if ( !this.options.title ) {
10488 title.html( " " );
10490 title.text( this.options.title );
10493 _createButtonPane: function() {
10494 this.uiDialogButtonPane = $( "<div>" )
10495 .addClass( "ui-dialog-buttonpane ui-widget-content ui-helper-clearfix" );
10497 this.uiButtonSet = $( "<div>" )
10498 .addClass( "ui-dialog-buttonset" )
10499 .appendTo( this.uiDialogButtonPane );
10501 this._createButtons();
10504 _createButtons: function() {
10506 buttons = this.options.buttons;
10508 // if we already have a button pane, remove it
10509 this.uiDialogButtonPane.remove();
10510 this.uiButtonSet.empty();
10512 if ( $.isEmptyObject( buttons ) || ($.isArray( buttons ) && !buttons.length) ) {
10513 this.uiDialog.removeClass( "ui-dialog-buttons" );
10517 $.each( buttons, function( name, props ) {
10518 var click, buttonOptions;
10519 props = $.isFunction( props ) ?
10520 { click: props, text: name } :
10522 // Default to a non-submitting button
10523 props = $.extend( { type: "button" }, props );
10524 // Change the context for the click callback to be the main element
10525 click = props.click;
10526 props.click = function() {
10527 click.apply( that.element[ 0 ], arguments );
10530 icons: props.icons,
10531 text: props.showText
10533 delete props.icons;
10534 delete props.showText;
10535 $( "<button></button>", props )
10536 .button( buttonOptions )
10537 .appendTo( that.uiButtonSet );
10539 this.uiDialog.addClass( "ui-dialog-buttons" );
10540 this.uiDialogButtonPane.appendTo( this.uiDialog );
10543 _makeDraggable: function() {
10545 options = this.options;
10547 function filteredUi( ui ) {
10549 position: ui.position,
10554 this.uiDialog.draggable({
10555 cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
10556 handle: ".ui-dialog-titlebar",
10557 containment: "document",
10558 start: function( event, ui ) {
10559 $( this ).addClass( "ui-dialog-dragging" );
10560 that._blockFrames();
10561 that._trigger( "dragStart", event, filteredUi( ui ) );
10563 drag: function( event, ui ) {
10564 that._trigger( "drag", event, filteredUi( ui ) );
10566 stop: function( event, ui ) {
10567 var left = ui.offset.left - that.document.scrollLeft(),
10568 top = ui.offset.top - that.document.scrollTop();
10570 options.position = {
10572 at: "left" + (left >= 0 ? "+" : "") + left + " " +
10573 "top" + (top >= 0 ? "+" : "") + top,
10576 $( this ).removeClass( "ui-dialog-dragging" );
10577 that._unblockFrames();
10578 that._trigger( "dragStop", event, filteredUi( ui ) );
10583 _makeResizable: function() {
10585 options = this.options,
10586 handles = options.resizable,
10587 // .ui-resizable has position: relative defined in the stylesheet
10588 // but dialogs have to use absolute or fixed positioning
10589 position = this.uiDialog.css("position"),
10590 resizeHandles = typeof handles === "string" ?
10592 "n,e,s,w,se,sw,ne,nw";
10594 function filteredUi( ui ) {
10596 originalPosition: ui.originalPosition,
10597 originalSize: ui.originalSize,
10598 position: ui.position,
10603 this.uiDialog.resizable({
10604 cancel: ".ui-dialog-content",
10605 containment: "document",
10606 alsoResize: this.element,
10607 maxWidth: options.maxWidth,
10608 maxHeight: options.maxHeight,
10609 minWidth: options.minWidth,
10610 minHeight: this._minHeight(),
10611 handles: resizeHandles,
10612 start: function( event, ui ) {
10613 $( this ).addClass( "ui-dialog-resizing" );
10614 that._blockFrames();
10615 that._trigger( "resizeStart", event, filteredUi( ui ) );
10617 resize: function( event, ui ) {
10618 that._trigger( "resize", event, filteredUi( ui ) );
10620 stop: function( event, ui ) {
10621 var offset = that.uiDialog.offset(),
10622 left = offset.left - that.document.scrollLeft(),
10623 top = offset.top - that.document.scrollTop();
10625 options.height = that.uiDialog.height();
10626 options.width = that.uiDialog.width();
10627 options.position = {
10629 at: "left" + (left >= 0 ? "+" : "") + left + " " +
10630 "top" + (top >= 0 ? "+" : "") + top,
10633 $( this ).removeClass( "ui-dialog-resizing" );
10634 that._unblockFrames();
10635 that._trigger( "resizeStop", event, filteredUi( ui ) );
10638 .css( "position", position );
10641 _trackFocus: function() {
10642 this._on( this.widget(), {
10643 focusin: function( event ) {
10644 this._makeFocusTarget();
10645 this._focusedElement = $( event.target );
10650 _makeFocusTarget: function() {
10651 this._untrackInstance();
10652 this._trackingInstances().unshift( this );
10655 _untrackInstance: function() {
10656 var instances = this._trackingInstances(),
10657 exists = $.inArray( this, instances );
10658 if ( exists !== -1 ) {
10659 instances.splice( exists, 1 );
10663 _trackingInstances: function() {
10664 var instances = this.document.data( "ui-dialog-instances" );
10665 if ( !instances ) {
10667 this.document.data( "ui-dialog-instances", instances );
10672 _minHeight: function() {
10673 var options = this.options;
10675 return options.height === "auto" ?
10676 options.minHeight :
10677 Math.min( options.minHeight, options.height );
10680 _position: function() {
10681 // Need to show the dialog to get the actual offset in the position plugin
10682 var isVisible = this.uiDialog.is( ":visible" );
10683 if ( !isVisible ) {
10684 this.uiDialog.show();
10686 this.uiDialog.position( this.options.position );
10687 if ( !isVisible ) {
10688 this.uiDialog.hide();
10692 _setOptions: function( options ) {
10695 resizableOptions = {};
10697 $.each( options, function( key, value ) {
10698 that._setOption( key, value );
10700 if ( key in that.sizeRelatedOptions ) {
10703 if ( key in that.resizableRelatedOptions ) {
10704 resizableOptions[ key ] = value;
10712 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
10713 this.uiDialog.resizable( "option", resizableOptions );
10717 _setOption: function( key, value ) {
10718 var isDraggable, isResizable,
10719 uiDialog = this.uiDialog;
10721 if ( key === "dialogClass" ) {
10723 .removeClass( this.options.dialogClass )
10724 .addClass( value );
10727 if ( key === "disabled" ) {
10731 this._super( key, value );
10733 if ( key === "appendTo" ) {
10734 this.uiDialog.appendTo( this._appendTo() );
10737 if ( key === "buttons" ) {
10738 this._createButtons();
10741 if ( key === "closeText" ) {
10742 this.uiDialogTitlebarClose.button({
10743 // Ensure that we always pass a string
10748 if ( key === "draggable" ) {
10749 isDraggable = uiDialog.is( ":data(ui-draggable)" );
10750 if ( isDraggable && !value ) {
10751 uiDialog.draggable( "destroy" );
10754 if ( !isDraggable && value ) {
10755 this._makeDraggable();
10759 if ( key === "position" ) {
10763 if ( key === "resizable" ) {
10764 // currently resizable, becoming non-resizable
10765 isResizable = uiDialog.is( ":data(ui-resizable)" );
10766 if ( isResizable && !value ) {
10767 uiDialog.resizable( "destroy" );
10770 // currently resizable, changing handles
10771 if ( isResizable && typeof value === "string" ) {
10772 uiDialog.resizable( "option", "handles", value );
10775 // currently non-resizable, becoming resizable
10776 if ( !isResizable && value !== false ) {
10777 this._makeResizable();
10781 if ( key === "title" ) {
10782 this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) );
10786 _size: function() {
10787 // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
10788 // divs will both have width and height set, so we need to reset them
10789 var nonContentHeight, minContentHeight, maxContentHeight,
10790 options = this.options;
10792 // Reset content sizing
10793 this.element.show().css({
10800 if ( options.minWidth > options.width ) {
10801 options.width = options.minWidth;
10804 // reset wrapper sizing
10805 // determine the height of all the non-content elements
10806 nonContentHeight = this.uiDialog.css({
10808 width: options.width
10811 minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
10812 maxContentHeight = typeof options.maxHeight === "number" ?
10813 Math.max( 0, options.maxHeight - nonContentHeight ) :
10816 if ( options.height === "auto" ) {
10818 minHeight: minContentHeight,
10819 maxHeight: maxContentHeight,
10823 this.element.height( Math.max( 0, options.height - nonContentHeight ) );
10826 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
10827 this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
10831 _blockFrames: function() {
10832 this.iframeBlocks = this.document.find( "iframe" ).map(function() {
10833 var iframe = $( this );
10835 return $( "<div>" )
10837 position: "absolute",
10838 width: iframe.outerWidth(),
10839 height: iframe.outerHeight()
10841 .appendTo( iframe.parent() )
10842 .offset( iframe.offset() )[0];
10846 _unblockFrames: function() {
10847 if ( this.iframeBlocks ) {
10848 this.iframeBlocks.remove();
10849 delete this.iframeBlocks;
10853 _allowInteraction: function( event ) {
10854 if ( $( event.target ).closest( ".ui-dialog" ).length ) {
10858 // TODO: Remove hack when datepicker implements
10859 // the .ui-front logic (#8989)
10860 return !!$( event.target ).closest( ".ui-datepicker" ).length;
10863 _createOverlay: function() {
10864 if ( !this.options.modal ) {
10868 // We use a delay in case the overlay is created from an
10869 // event that we're going to be cancelling (#2804)
10870 var isOpening = true;
10871 this._delay(function() {
10875 if ( !this.document.data( "ui-dialog-overlays" ) ) {
10877 // Prevent use of anchors and inputs
10878 // Using _on() for an event handler shared across many instances is
10879 // safe because the dialogs stack and must be closed in reverse order
10880 this._on( this.document, {
10881 focusin: function( event ) {
10886 if ( !this._allowInteraction( event ) ) {
10887 event.preventDefault();
10888 this._trackingInstances()[ 0 ]._focusTabbable();
10894 this.overlay = $( "<div>" )
10895 .addClass( "ui-widget-overlay ui-front" )
10896 .appendTo( this._appendTo() );
10897 this._on( this.overlay, {
10898 mousedown: "_keepFocus"
10900 this.document.data( "ui-dialog-overlays",
10901 (this.document.data( "ui-dialog-overlays" ) || 0) + 1 );
10904 _destroyOverlay: function() {
10905 if ( !this.options.modal ) {
10909 if ( this.overlay ) {
10910 var overlays = this.document.data( "ui-dialog-overlays" ) - 1;
10914 .unbind( "focusin" )
10915 .removeData( "ui-dialog-overlays" );
10917 this.document.data( "ui-dialog-overlays", overlays );
10920 this.overlay.remove();
10921 this.overlay = null;
10928 * jQuery UI Progressbar 1.11.3
10929 * http://jqueryui.com
10931 * Copyright jQuery Foundation and other contributors
10932 * Released under the MIT license.
10933 * http://jquery.org/license
10935 * http://api.jqueryui.com/progressbar/
10939 var progressbar = $.widget( "ui.progressbar", {
10951 _create: function() {
10952 // Constrain initial value
10953 this.oldValue = this.options.value = this._constrainedValue();
10956 .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
10958 // Only set static values, aria-valuenow and aria-valuemax are
10959 // set inside _refreshValue()
10960 role: "progressbar",
10961 "aria-valuemin": this.min
10964 this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" )
10965 .appendTo( this.element );
10967 this._refreshValue();
10970 _destroy: function() {
10972 .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
10973 .removeAttr( "role" )
10974 .removeAttr( "aria-valuemin" )
10975 .removeAttr( "aria-valuemax" )
10976 .removeAttr( "aria-valuenow" );
10978 this.valueDiv.remove();
10981 value: function( newValue ) {
10982 if ( newValue === undefined ) {
10983 return this.options.value;
10986 this.options.value = this._constrainedValue( newValue );
10987 this._refreshValue();
10990 _constrainedValue: function( newValue ) {
10991 if ( newValue === undefined ) {
10992 newValue = this.options.value;
10995 this.indeterminate = newValue === false;
10998 if ( typeof newValue !== "number" ) {
11002 return this.indeterminate ? false :
11003 Math.min( this.options.max, Math.max( this.min, newValue ) );
11006 _setOptions: function( options ) {
11007 // Ensure "value" option is set after other values (like max)
11008 var value = options.value;
11009 delete options.value;
11011 this._super( options );
11013 this.options.value = this._constrainedValue( value );
11014 this._refreshValue();
11017 _setOption: function( key, value ) {
11018 if ( key === "max" ) {
11019 // Don't allow a max less than min
11020 value = Math.max( this.min, value );
11022 if ( key === "disabled" ) {
11024 .toggleClass( "ui-state-disabled", !!value )
11025 .attr( "aria-disabled", value );
11027 this._super( key, value );
11030 _percentage: function() {
11031 return this.indeterminate ? 100 : 100 * ( this.options.value - this.min ) / ( this.options.max - this.min );
11034 _refreshValue: function() {
11035 var value = this.options.value,
11036 percentage = this._percentage();
11039 .toggle( this.indeterminate || value > this.min )
11040 .toggleClass( "ui-corner-right", value === this.options.max )
11041 .width( percentage.toFixed(0) + "%" );
11043 this.element.toggleClass( "ui-progressbar-indeterminate", this.indeterminate );
11045 if ( this.indeterminate ) {
11046 this.element.removeAttr( "aria-valuenow" );
11047 if ( !this.overlayDiv ) {
11048 this.overlayDiv = $( "<div class='ui-progressbar-overlay'></div>" ).appendTo( this.valueDiv );
11051 this.element.attr({
11052 "aria-valuemax": this.options.max,
11053 "aria-valuenow": value
11055 if ( this.overlayDiv ) {
11056 this.overlayDiv.remove();
11057 this.overlayDiv = null;
11061 if ( this.oldValue !== value ) {
11062 this.oldValue = value;
11063 this._trigger( "change" );
11065 if ( value === this.options.max ) {
11066 this._trigger( "complete" );
11073 * jQuery UI Selectmenu 1.11.3
11074 * http://jqueryui.com
11076 * Copyright jQuery Foundation and other contributors
11077 * Released under the MIT license.
11078 * http://jquery.org/license
11080 * http://api.jqueryui.com/selectmenu
11084 var selectmenu = $.widget( "ui.selectmenu", {
11086 defaultElement: "<select>",
11091 button: "ui-icon-triangle-1-s"
11108 _create: function() {
11109 var selectmenuId = this.element.uniqueId().attr( "id" );
11111 element: selectmenuId,
11112 button: selectmenuId + "-button",
11113 menu: selectmenuId + "-menu"
11116 this._drawButton();
11119 if ( this.options.disabled ) {
11124 _drawButton: function() {
11127 // Associate existing label with the new button
11128 this.label = $( "label[for='" + this.ids.element + "']" ).attr( "for", this.ids.button );
11129 this._on( this.label, {
11130 click: function( event ) {
11131 this.button.focus();
11132 event.preventDefault();
11136 // Hide original select element
11137 this.element.hide();
11140 this.button = $( "<span>", {
11141 "class": "ui-selectmenu-button ui-widget ui-state-default ui-corner-all",
11142 tabindex: this.options.disabled ? -1 : 0,
11143 id: this.ids.button,
11145 "aria-expanded": "false",
11146 "aria-autocomplete": "list",
11147 "aria-owns": this.ids.menu,
11148 "aria-haspopup": "true"
11150 .insertAfter( this.element );
11153 "class": "ui-icon " + this.options.icons.button
11155 .prependTo( this.button );
11157 this.buttonText = $( "<span>", {
11158 "class": "ui-selectmenu-text"
11160 .appendTo( this.button );
11162 this._setText( this.buttonText, this.element.find( "option:selected" ).text() );
11163 this._resizeButton();
11165 this._on( this.button, this._buttonEvents );
11166 this.button.one( "focusin", function() {
11168 // Delay rendering the menu items until the button receives focus.
11169 // The menu may have already been rendered via a programmatic open.
11170 if ( !that.menuItems ) {
11171 that._refreshMenu();
11174 this._hoverable( this.button );
11175 this._focusable( this.button );
11178 _drawMenu: function() {
11182 this.menu = $( "<ul>", {
11183 "aria-hidden": "true",
11184 "aria-labelledby": this.ids.button,
11189 this.menuWrap = $( "<div>", {
11190 "class": "ui-selectmenu-menu ui-front"
11192 .append( this.menu )
11193 .appendTo( this._appendTo() );
11195 // Initialize menu widget
11196 this.menuInstance = this.menu
11199 select: function( event, ui ) {
11200 event.preventDefault();
11203 // If the item was selected via a click, the text selection
11204 // will be destroyed in IE
11205 that._setSelection();
11207 that._select( ui.item.data( "ui-selectmenu-item" ), event );
11209 focus: function( event, ui ) {
11210 var item = ui.item.data( "ui-selectmenu-item" );
11212 // Prevent inital focus from firing and check if its a newly focused item
11213 if ( that.focusIndex != null && item.index !== that.focusIndex ) {
11214 that._trigger( "focus", event, { item: item } );
11215 if ( !that.isOpen ) {
11216 that._select( item, event );
11219 that.focusIndex = item.index;
11221 that.button.attr( "aria-activedescendant",
11222 that.menuItems.eq( item.index ).attr( "id" ) );
11225 .menu( "instance" );
11227 // Adjust menu styles to dropdown
11229 .addClass( "ui-corner-bottom" )
11230 .removeClass( "ui-corner-all" );
11232 // Don't close the menu on mouseleave
11233 this.menuInstance._off( this.menu, "mouseleave" );
11235 // Cancel the menu's collapseAll on document click
11236 this.menuInstance._closeOnDocumentClick = function() {
11240 // Selects often contain empty items, but never contain dividers
11241 this.menuInstance._isDivider = function() {
11246 refresh: function() {
11247 this._refreshMenu();
11248 this._setText( this.buttonText, this._getSelectedItem().text() );
11249 if ( !this.options.width ) {
11250 this._resizeButton();
11254 _refreshMenu: function() {
11258 options = this.element.find( "option" );
11260 if ( !options.length ) {
11264 this._parseOptions( options );
11265 this._renderMenu( this.menu, this.items );
11267 this.menuInstance.refresh();
11268 this.menuItems = this.menu.find( "li" ).not( ".ui-selectmenu-optgroup" );
11270 item = this._getSelectedItem();
11272 // Update the menu to have the correct item focused
11273 this.menuInstance.focus( null, item );
11274 this._setAria( item.data( "ui-selectmenu-item" ) );
11276 // Set disabled state
11277 this._setOption( "disabled", this.element.prop( "disabled" ) );
11280 open: function( event ) {
11281 if ( this.options.disabled ) {
11285 // If this is the first time the menu is being opened, render the items
11286 if ( !this.menuItems ) {
11287 this._refreshMenu();
11290 // Menu clears focus on close, reset focus to selected item
11291 this.menu.find( ".ui-state-focus" ).removeClass( "ui-state-focus" );
11292 this.menuInstance.focus( null, this._getSelectedItem() );
11295 this.isOpen = true;
11296 this._toggleAttr();
11297 this._resizeMenu();
11300 this._on( this.document, this._documentClick );
11302 this._trigger( "open", event );
11305 _position: function() {
11306 this.menuWrap.position( $.extend( { of: this.button }, this.options.position ) );
11309 close: function( event ) {
11310 if ( !this.isOpen ) {
11314 this.isOpen = false;
11315 this._toggleAttr();
11318 this._off( this.document );
11320 this._trigger( "close", event );
11323 widget: function() {
11324 return this.button;
11327 menuWidget: function() {
11331 _renderMenu: function( ul, items ) {
11333 currentOptgroup = "";
11335 $.each( items, function( index, item ) {
11336 if ( item.optgroup !== currentOptgroup ) {
11338 "class": "ui-selectmenu-optgroup ui-menu-divider" +
11339 ( item.element.parent( "optgroup" ).prop( "disabled" ) ?
11340 " ui-state-disabled" :
11342 text: item.optgroup
11346 currentOptgroup = item.optgroup;
11349 that._renderItemData( ul, item );
11353 _renderItemData: function( ul, item ) {
11354 return this._renderItem( ul, item ).data( "ui-selectmenu-item", item );
11357 _renderItem: function( ul, item ) {
11358 var li = $( "<li>" );
11360 if ( item.disabled ) {
11361 li.addClass( "ui-state-disabled" );
11363 this._setText( li, item.label );
11365 return li.appendTo( ul );
11368 _setText: function( element, value ) {
11370 element.text( value );
11372 element.html( " " );
11376 _move: function( direction, event ) {
11378 filter = ".ui-menu-item";
11380 if ( this.isOpen ) {
11381 item = this.menuItems.eq( this.focusIndex );
11383 item = this.menuItems.eq( this.element[ 0 ].selectedIndex );
11384 filter += ":not(.ui-state-disabled)";
11387 if ( direction === "first" || direction === "last" ) {
11388 next = item[ direction === "first" ? "prevAll" : "nextAll" ]( filter ).eq( -1 );
11390 next = item[ direction + "All" ]( filter ).eq( 0 );
11393 if ( next.length ) {
11394 this.menuInstance.focus( event, next );
11398 _getSelectedItem: function() {
11399 return this.menuItems.eq( this.element[ 0 ].selectedIndex );
11402 _toggle: function( event ) {
11403 this[ this.isOpen ? "close" : "open" ]( event );
11406 _setSelection: function() {
11409 if ( !this.range ) {
11413 if ( window.getSelection ) {
11414 selection = window.getSelection();
11415 selection.removeAllRanges();
11416 selection.addRange( this.range );
11420 this.range.select();
11424 // Setting the text selection kills the button focus in IE, but
11425 // restoring the focus doesn't kill the selection.
11426 this.button.focus();
11430 mousedown: function( event ) {
11431 if ( !this.isOpen ) {
11435 if ( !$( event.target ).closest( ".ui-selectmenu-menu, #" + this.ids.button ).length ) {
11436 this.close( event );
11443 // Prevent text selection from being reset when interacting with the selectmenu (#10144)
11444 mousedown: function() {
11447 if ( window.getSelection ) {
11448 selection = window.getSelection();
11449 if ( selection.rangeCount ) {
11450 this.range = selection.getRangeAt( 0 );
11455 this.range = document.selection.createRange();
11459 click: function( event ) {
11460 this._setSelection();
11461 this._toggle( event );
11464 keydown: function( event ) {
11465 var preventDefault = true;
11466 switch ( event.keyCode ) {
11467 case $.ui.keyCode.TAB:
11468 case $.ui.keyCode.ESCAPE:
11469 this.close( event );
11470 preventDefault = false;
11472 case $.ui.keyCode.ENTER:
11473 if ( this.isOpen ) {
11474 this._selectFocusedItem( event );
11477 case $.ui.keyCode.UP:
11478 if ( event.altKey ) {
11479 this._toggle( event );
11481 this._move( "prev", event );
11484 case $.ui.keyCode.DOWN:
11485 if ( event.altKey ) {
11486 this._toggle( event );
11488 this._move( "next", event );
11491 case $.ui.keyCode.SPACE:
11492 if ( this.isOpen ) {
11493 this._selectFocusedItem( event );
11495 this._toggle( event );
11498 case $.ui.keyCode.LEFT:
11499 this._move( "prev", event );
11501 case $.ui.keyCode.RIGHT:
11502 this._move( "next", event );
11504 case $.ui.keyCode.HOME:
11505 case $.ui.keyCode.PAGE_UP:
11506 this._move( "first", event );
11508 case $.ui.keyCode.END:
11509 case $.ui.keyCode.PAGE_DOWN:
11510 this._move( "last", event );
11513 this.menu.trigger( event );
11514 preventDefault = false;
11517 if ( preventDefault ) {
11518 event.preventDefault();
11523 _selectFocusedItem: function( event ) {
11524 var item = this.menuItems.eq( this.focusIndex );
11525 if ( !item.hasClass( "ui-state-disabled" ) ) {
11526 this._select( item.data( "ui-selectmenu-item" ), event );
11530 _select: function( item, event ) {
11531 var oldIndex = this.element[ 0 ].selectedIndex;
11533 // Change native select element
11534 this.element[ 0 ].selectedIndex = item.index;
11535 this._setText( this.buttonText, item.label );
11536 this._setAria( item );
11537 this._trigger( "select", event, { item: item } );
11539 if ( item.index !== oldIndex ) {
11540 this._trigger( "change", event, { item: item } );
11543 this.close( event );
11546 _setAria: function( item ) {
11547 var id = this.menuItems.eq( item.index ).attr( "id" );
11550 "aria-labelledby": id,
11551 "aria-activedescendant": id
11553 this.menu.attr( "aria-activedescendant", id );
11556 _setOption: function( key, value ) {
11557 if ( key === "icons" ) {
11558 this.button.find( "span.ui-icon" )
11559 .removeClass( this.options.icons.button )
11560 .addClass( value.button );
11563 this._super( key, value );
11565 if ( key === "appendTo" ) {
11566 this.menuWrap.appendTo( this._appendTo() );
11569 if ( key === "disabled" ) {
11570 this.menuInstance.option( "disabled", value );
11572 .toggleClass( "ui-state-disabled", value )
11573 .attr( "aria-disabled", value );
11575 this.element.prop( "disabled", value );
11577 this.button.attr( "tabindex", -1 );
11580 this.button.attr( "tabindex", 0 );
11584 if ( key === "width" ) {
11585 this._resizeButton();
11589 _appendTo: function() {
11590 var element = this.options.appendTo;
11593 element = element.jquery || element.nodeType ?
11595 this.document.find( element ).eq( 0 );
11598 if ( !element || !element[ 0 ] ) {
11599 element = this.element.closest( ".ui-front" );
11602 if ( !element.length ) {
11603 element = this.document[ 0 ].body;
11609 _toggleAttr: function() {
11611 .toggleClass( "ui-corner-top", this.isOpen )
11612 .toggleClass( "ui-corner-all", !this.isOpen )
11613 .attr( "aria-expanded", this.isOpen );
11614 this.menuWrap.toggleClass( "ui-selectmenu-open", this.isOpen );
11615 this.menu.attr( "aria-hidden", !this.isOpen );
11618 _resizeButton: function() {
11619 var width = this.options.width;
11622 width = this.element.show().outerWidth();
11623 this.element.hide();
11626 this.button.outerWidth( width );
11629 _resizeMenu: function() {
11630 this.menu.outerWidth( Math.max(
11631 this.button.outerWidth(),
11634 // IE10 wraps long text (possibly a rounding bug)
11635 // so we add 1px to avoid the wrapping
11636 this.menu.width( "" ).outerWidth() + 1
11640 _getCreateOptions: function() {
11641 return { disabled: this.element.prop( "disabled" ) };
11644 _parseOptions: function( options ) {
11646 options.each(function( index, item ) {
11647 var option = $( item ),
11648 optgroup = option.parent( "optgroup" );
11652 value: option.val(),
11653 label: option.text(),
11654 optgroup: optgroup.attr( "label" ) || "",
11655 disabled: optgroup.prop( "disabled" ) || option.prop( "disabled" )
11661 _destroy: function() {
11662 this.menuWrap.remove();
11663 this.button.remove();
11664 this.element.show();
11665 this.element.removeUniqueId();
11666 this.label.attr( "for", this.ids.element );
11672 * jQuery UI Slider 1.11.3
11673 * http://jqueryui.com
11675 * Copyright jQuery Foundation and other contributors
11676 * Released under the MIT license.
11677 * http://jquery.org/license
11679 * http://api.jqueryui.com/slider/
11683 var slider = $.widget( "ui.slider", $.ui.mouse, {
11685 widgetEventPrefix: "slide",
11692 orientation: "horizontal",
11705 // number of pages in a slider
11706 // (how many times can you page up/down to go through the whole range)
11709 _create: function() {
11710 this._keySliding = false;
11711 this._mouseSliding = false;
11712 this._animateOff = true;
11713 this._handleIndex = null;
11714 this._detectOrientation();
11716 this._calculateNewMax();
11719 .addClass( "ui-slider" +
11720 " ui-slider-" + this.orientation +
11722 " ui-widget-content" +
11726 this._setOption( "disabled", this.options.disabled );
11728 this._animateOff = false;
11731 _refresh: function() {
11732 this._createRange();
11733 this._createHandles();
11734 this._setupEvents();
11735 this._refreshValue();
11738 _createHandles: function() {
11739 var i, handleCount,
11740 options = this.options,
11741 existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ),
11742 handle = "<span class='ui-slider-handle ui-state-default ui-corner-all' tabindex='0'></span>",
11745 handleCount = ( options.values && options.values.length ) || 1;
11747 if ( existingHandles.length > handleCount ) {
11748 existingHandles.slice( handleCount ).remove();
11749 existingHandles = existingHandles.slice( 0, handleCount );
11752 for ( i = existingHandles.length; i < handleCount; i++ ) {
11753 handles.push( handle );
11756 this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
11758 this.handle = this.handles.eq( 0 );
11760 this.handles.each(function( i ) {
11761 $( this ).data( "ui-slider-handle-index", i );
11765 _createRange: function() {
11766 var options = this.options,
11769 if ( options.range ) {
11770 if ( options.range === true ) {
11771 if ( !options.values ) {
11772 options.values = [ this._valueMin(), this._valueMin() ];
11773 } else if ( options.values.length && options.values.length !== 2 ) {
11774 options.values = [ options.values[0], options.values[0] ];
11775 } else if ( $.isArray( options.values ) ) {
11776 options.values = options.values.slice(0);
11780 if ( !this.range || !this.range.length ) {
11781 this.range = $( "<div></div>" )
11782 .appendTo( this.element );
11784 classes = "ui-slider-range" +
11785 // note: this isn't the most fittingly semantic framework class for this element,
11786 // but worked best visually with a variety of themes
11787 " ui-widget-header ui-corner-all";
11789 this.range.removeClass( "ui-slider-range-min ui-slider-range-max" )
11790 // Handle range switching from true to min/max
11797 this.range.addClass( classes +
11798 ( ( options.range === "min" || options.range === "max" ) ? " ui-slider-range-" + options.range : "" ) );
11800 if ( this.range ) {
11801 this.range.remove();
11807 _setupEvents: function() {
11808 this._off( this.handles );
11809 this._on( this.handles, this._handleEvents );
11810 this._hoverable( this.handles );
11811 this._focusable( this.handles );
11814 _destroy: function() {
11815 this.handles.remove();
11816 if ( this.range ) {
11817 this.range.remove();
11821 .removeClass( "ui-slider" +
11822 " ui-slider-horizontal" +
11823 " ui-slider-vertical" +
11825 " ui-widget-content" +
11826 " ui-corner-all" );
11828 this._mouseDestroy();
11831 _mouseCapture: function( event ) {
11832 var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
11836 if ( o.disabled ) {
11840 this.elementSize = {
11841 width: this.element.outerWidth(),
11842 height: this.element.outerHeight()
11844 this.elementOffset = this.element.offset();
11846 position = { x: event.pageX, y: event.pageY };
11847 normValue = this._normValueFromMouse( position );
11848 distance = this._valueMax() - this._valueMin() + 1;
11849 this.handles.each(function( i ) {
11850 var thisDistance = Math.abs( normValue - that.values(i) );
11851 if (( distance > thisDistance ) ||
11852 ( distance === thisDistance &&
11853 (i === that._lastChangedValue || that.values(i) === o.min ))) {
11854 distance = thisDistance;
11855 closestHandle = $( this );
11860 allowed = this._start( event, index );
11861 if ( allowed === false ) {
11864 this._mouseSliding = true;
11866 this._handleIndex = index;
11869 .addClass( "ui-state-active" )
11872 offset = closestHandle.offset();
11873 mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
11874 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
11875 left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
11876 top: event.pageY - offset.top -
11877 ( closestHandle.height() / 2 ) -
11878 ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) -
11879 ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) +
11880 ( parseInt( closestHandle.css("marginTop"), 10 ) || 0)
11883 if ( !this.handles.hasClass( "ui-state-hover" ) ) {
11884 this._slide( event, index, normValue );
11886 this._animateOff = true;
11890 _mouseStart: function() {
11894 _mouseDrag: function( event ) {
11895 var position = { x: event.pageX, y: event.pageY },
11896 normValue = this._normValueFromMouse( position );
11898 this._slide( event, this._handleIndex, normValue );
11903 _mouseStop: function( event ) {
11904 this.handles.removeClass( "ui-state-active" );
11905 this._mouseSliding = false;
11907 this._stop( event, this._handleIndex );
11908 this._change( event, this._handleIndex );
11910 this._handleIndex = null;
11911 this._clickOffset = null;
11912 this._animateOff = false;
11917 _detectOrientation: function() {
11918 this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
11921 _normValueFromMouse: function( position ) {
11928 if ( this.orientation === "horizontal" ) {
11929 pixelTotal = this.elementSize.width;
11930 pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
11932 pixelTotal = this.elementSize.height;
11933 pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );
11936 percentMouse = ( pixelMouse / pixelTotal );
11937 if ( percentMouse > 1 ) {
11940 if ( percentMouse < 0 ) {
11943 if ( this.orientation === "vertical" ) {
11944 percentMouse = 1 - percentMouse;
11947 valueTotal = this._valueMax() - this._valueMin();
11948 valueMouse = this._valueMin() + percentMouse * valueTotal;
11950 return this._trimAlignValue( valueMouse );
11953 _start: function( event, index ) {
11955 handle: this.handles[ index ],
11956 value: this.value()
11958 if ( this.options.values && this.options.values.length ) {
11959 uiHash.value = this.values( index );
11960 uiHash.values = this.values();
11962 return this._trigger( "start", event, uiHash );
11965 _slide: function( event, index, newVal ) {
11970 if ( this.options.values && this.options.values.length ) {
11971 otherVal = this.values( index ? 0 : 1 );
11973 if ( ( this.options.values.length === 2 && this.options.range === true ) &&
11974 ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )
11979 if ( newVal !== this.values( index ) ) {
11980 newValues = this.values();
11981 newValues[ index ] = newVal;
11982 // A slide can be canceled by returning false from the slide callback
11983 allowed = this._trigger( "slide", event, {
11984 handle: this.handles[ index ],
11988 otherVal = this.values( index ? 0 : 1 );
11989 if ( allowed !== false ) {
11990 this.values( index, newVal );
11994 if ( newVal !== this.value() ) {
11995 // A slide can be canceled by returning false from the slide callback
11996 allowed = this._trigger( "slide", event, {
11997 handle: this.handles[ index ],
12000 if ( allowed !== false ) {
12001 this.value( newVal );
12007 _stop: function( event, index ) {
12009 handle: this.handles[ index ],
12010 value: this.value()
12012 if ( this.options.values && this.options.values.length ) {
12013 uiHash.value = this.values( index );
12014 uiHash.values = this.values();
12017 this._trigger( "stop", event, uiHash );
12020 _change: function( event, index ) {
12021 if ( !this._keySliding && !this._mouseSliding ) {
12023 handle: this.handles[ index ],
12024 value: this.value()
12026 if ( this.options.values && this.options.values.length ) {
12027 uiHash.value = this.values( index );
12028 uiHash.values = this.values();
12031 //store the last changed value index for reference when handles overlap
12032 this._lastChangedValue = index;
12034 this._trigger( "change", event, uiHash );
12038 value: function( newValue ) {
12039 if ( arguments.length ) {
12040 this.options.value = this._trimAlignValue( newValue );
12041 this._refreshValue();
12042 this._change( null, 0 );
12046 return this._value();
12049 values: function( index, newValue ) {
12054 if ( arguments.length > 1 ) {
12055 this.options.values[ index ] = this._trimAlignValue( newValue );
12056 this._refreshValue();
12057 this._change( null, index );
12061 if ( arguments.length ) {
12062 if ( $.isArray( arguments[ 0 ] ) ) {
12063 vals = this.options.values;
12064 newValues = arguments[ 0 ];
12065 for ( i = 0; i < vals.length; i += 1 ) {
12066 vals[ i ] = this._trimAlignValue( newValues[ i ] );
12067 this._change( null, i );
12069 this._refreshValue();
12071 if ( this.options.values && this.options.values.length ) {
12072 return this._values( index );
12074 return this.value();
12078 return this._values();
12082 _setOption: function( key, value ) {
12086 if ( key === "range" && this.options.range === true ) {
12087 if ( value === "min" ) {
12088 this.options.value = this._values( 0 );
12089 this.options.values = null;
12090 } else if ( value === "max" ) {
12091 this.options.value = this._values( this.options.values.length - 1 );
12092 this.options.values = null;
12096 if ( $.isArray( this.options.values ) ) {
12097 valsLength = this.options.values.length;
12100 if ( key === "disabled" ) {
12101 this.element.toggleClass( "ui-state-disabled", !!value );
12104 this._super( key, value );
12107 case "orientation":
12108 this._detectOrientation();
12110 .removeClass( "ui-slider-horizontal ui-slider-vertical" )
12111 .addClass( "ui-slider-" + this.orientation );
12112 this._refreshValue();
12114 // Reset positioning from previous orientation
12115 this.handles.css( value === "horizontal" ? "bottom" : "left", "" );
12118 this._animateOff = true;
12119 this._refreshValue();
12120 this._change( null, 0 );
12121 this._animateOff = false;
12124 this._animateOff = true;
12125 this._refreshValue();
12126 for ( i = 0; i < valsLength; i += 1 ) {
12127 this._change( null, i );
12129 this._animateOff = false;
12134 this._animateOff = true;
12135 this._calculateNewMax();
12136 this._refreshValue();
12137 this._animateOff = false;
12140 this._animateOff = true;
12142 this._animateOff = false;
12147 //internal value getter
12148 // _value() returns value trimmed by min and max, aligned by step
12149 _value: function() {
12150 var val = this.options.value;
12151 val = this._trimAlignValue( val );
12156 //internal values getter
12157 // _values() returns array of values trimmed by min and max, aligned by step
12158 // _values( index ) returns single value trimmed by min and max, aligned by step
12159 _values: function( index ) {
12164 if ( arguments.length ) {
12165 val = this.options.values[ index ];
12166 val = this._trimAlignValue( val );
12169 } else if ( this.options.values && this.options.values.length ) {
12170 // .slice() creates a copy of the array
12171 // this copy gets trimmed by min and max and then returned
12172 vals = this.options.values.slice();
12173 for ( i = 0; i < vals.length; i += 1) {
12174 vals[ i ] = this._trimAlignValue( vals[ i ] );
12183 // returns the step-aligned value that val is closest to, between (inclusive) min and max
12184 _trimAlignValue: function( val ) {
12185 if ( val <= this._valueMin() ) {
12186 return this._valueMin();
12188 if ( val >= this._valueMax() ) {
12189 return this._valueMax();
12191 var step = ( this.options.step > 0 ) ? this.options.step : 1,
12192 valModStep = (val - this._valueMin()) % step,
12193 alignValue = val - valModStep;
12195 if ( Math.abs(valModStep) * 2 >= step ) {
12196 alignValue += ( valModStep > 0 ) ? step : ( -step );
12199 // Since JavaScript has problems with large floats, round
12200 // the final value to 5 digits after the decimal point (see #4124)
12201 return parseFloat( alignValue.toFixed(5) );
12204 _calculateNewMax: function() {
12205 var max = this.options.max,
12206 min = this._valueMin(),
12207 step = this.options.step,
12208 aboveMin = Math.floor( ( max - min ) / step ) * step;
12209 max = aboveMin + min;
12210 this.max = parseFloat( max.toFixed( this._precision() ) );
12213 _precision: function() {
12214 var precision = this._precisionOf( this.options.step );
12215 if ( this.options.min !== null ) {
12216 precision = Math.max( precision, this._precisionOf( this.options.min ) );
12221 _precisionOf: function( num ) {
12222 var str = num.toString(),
12223 decimal = str.indexOf( "." );
12224 return decimal === -1 ? 0 : str.length - decimal - 1;
12227 _valueMin: function() {
12228 return this.options.min;
12231 _valueMax: function() {
12235 _refreshValue: function() {
12236 var lastValPercent, valPercent, value, valueMin, valueMax,
12237 oRange = this.options.range,
12240 animate = ( !this._animateOff ) ? o.animate : false,
12243 if ( this.options.values && this.options.values.length ) {
12244 this.handles.each(function( i ) {
12245 valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100;
12246 _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
12247 $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
12248 if ( that.options.range === true ) {
12249 if ( that.orientation === "horizontal" ) {
12251 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate );
12254 that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
12258 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate );
12261 that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
12265 lastValPercent = valPercent;
12268 value = this.value();
12269 valueMin = this._valueMin();
12270 valueMax = this._valueMax();
12271 valPercent = ( valueMax !== valueMin ) ?
12272 ( value - valueMin ) / ( valueMax - valueMin ) * 100 :
12274 _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
12275 this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
12277 if ( oRange === "min" && this.orientation === "horizontal" ) {
12278 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate );
12280 if ( oRange === "max" && this.orientation === "horizontal" ) {
12281 this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
12283 if ( oRange === "min" && this.orientation === "vertical" ) {
12284 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate );
12286 if ( oRange === "max" && this.orientation === "vertical" ) {
12287 this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
12293 keydown: function( event ) {
12294 var allowed, curVal, newVal, step,
12295 index = $( event.target ).data( "ui-slider-handle-index" );
12297 switch ( event.keyCode ) {
12298 case $.ui.keyCode.HOME:
12299 case $.ui.keyCode.END:
12300 case $.ui.keyCode.PAGE_UP:
12301 case $.ui.keyCode.PAGE_DOWN:
12302 case $.ui.keyCode.UP:
12303 case $.ui.keyCode.RIGHT:
12304 case $.ui.keyCode.DOWN:
12305 case $.ui.keyCode.LEFT:
12306 event.preventDefault();
12307 if ( !this._keySliding ) {
12308 this._keySliding = true;
12309 $( event.target ).addClass( "ui-state-active" );
12310 allowed = this._start( event, index );
12311 if ( allowed === false ) {
12318 step = this.options.step;
12319 if ( this.options.values && this.options.values.length ) {
12320 curVal = newVal = this.values( index );
12322 curVal = newVal = this.value();
12325 switch ( event.keyCode ) {
12326 case $.ui.keyCode.HOME:
12327 newVal = this._valueMin();
12329 case $.ui.keyCode.END:
12330 newVal = this._valueMax();
12332 case $.ui.keyCode.PAGE_UP:
12333 newVal = this._trimAlignValue(
12334 curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages )
12337 case $.ui.keyCode.PAGE_DOWN:
12338 newVal = this._trimAlignValue(
12339 curVal - ( (this._valueMax() - this._valueMin()) / this.numPages ) );
12341 case $.ui.keyCode.UP:
12342 case $.ui.keyCode.RIGHT:
12343 if ( curVal === this._valueMax() ) {
12346 newVal = this._trimAlignValue( curVal + step );
12348 case $.ui.keyCode.DOWN:
12349 case $.ui.keyCode.LEFT:
12350 if ( curVal === this._valueMin() ) {
12353 newVal = this._trimAlignValue( curVal - step );
12357 this._slide( event, index, newVal );
12359 keyup: function( event ) {
12360 var index = $( event.target ).data( "ui-slider-handle-index" );
12362 if ( this._keySliding ) {
12363 this._keySliding = false;
12364 this._stop( event, index );
12365 this._change( event, index );
12366 $( event.target ).removeClass( "ui-state-active" );
12374 * jQuery UI Spinner 1.11.3
12375 * http://jqueryui.com
12377 * Copyright jQuery Foundation and other contributors
12378 * Released under the MIT license.
12379 * http://jquery.org/license
12381 * http://api.jqueryui.com/spinner/
12385 function spinner_modifier( fn ) {
12386 return function() {
12387 var previous = this.element.val();
12388 fn.apply( this, arguments );
12390 if ( previous !== this.element.val() ) {
12391 this._trigger( "change" );
12396 var spinner = $.widget( "ui.spinner", {
12398 defaultElement: "<input>",
12399 widgetEventPrefix: "spin",
12403 down: "ui-icon-triangle-1-s",
12404 up: "ui-icon-triangle-1-n"
12409 numberFormat: null,
12419 _create: function() {
12420 // handle string values that need to be parsed
12421 this._setOption( "max", this.options.max );
12422 this._setOption( "min", this.options.min );
12423 this._setOption( "step", this.options.step );
12425 // Only format if there is a value, prevents the field from being marked
12426 // as invalid in Firefox, see #9573.
12427 if ( this.value() !== "" ) {
12428 // Format the value, but don't constrain.
12429 this._value( this.element.val(), true );
12433 this._on( this._events );
12436 // turning off autocomplete prevents the browser from remembering the
12437 // value when navigating through history, so we re-enable autocomplete
12438 // if the page is unloaded before the widget is destroyed. #7790
12439 this._on( this.window, {
12440 beforeunload: function() {
12441 this.element.removeAttr( "autocomplete" );
12446 _getCreateOptions: function() {
12448 element = this.element;
12450 $.each( [ "min", "max", "step" ], function( i, option ) {
12451 var value = element.attr( option );
12452 if ( value !== undefined && value.length ) {
12453 options[ option ] = value;
12461 keydown: function( event ) {
12462 if ( this._start( event ) && this._keydown( event ) ) {
12463 event.preventDefault();
12467 focus: function() {
12468 this.previous = this.element.val();
12470 blur: function( event ) {
12471 if ( this.cancelBlur ) {
12472 delete this.cancelBlur;
12478 if ( this.previous !== this.element.val() ) {
12479 this._trigger( "change", event );
12482 mousewheel: function( event, delta ) {
12486 if ( !this.spinning && !this._start( event ) ) {
12490 this._spin( (delta > 0 ? 1 : -1) * this.options.step, event );
12491 clearTimeout( this.mousewheelTimer );
12492 this.mousewheelTimer = this._delay(function() {
12493 if ( this.spinning ) {
12494 this._stop( event );
12497 event.preventDefault();
12499 "mousedown .ui-spinner-button": function( event ) {
12502 // We never want the buttons to have focus; whenever the user is
12503 // interacting with the spinner, the focus should be on the input.
12504 // If the input is focused then this.previous is properly set from
12505 // when the input first received focus. If the input is not focused
12506 // then we need to set this.previous based on the value before spinning.
12507 previous = this.element[0] === this.document[0].activeElement ?
12508 this.previous : this.element.val();
12509 function checkFocus() {
12510 var isActive = this.element[0] === this.document[0].activeElement;
12512 this.element.focus();
12513 this.previous = previous;
12515 // IE sets focus asynchronously, so we need to check if focus
12516 // moved off of the input because the user clicked on the button.
12517 this._delay(function() {
12518 this.previous = previous;
12523 // ensure focus is on (or stays on) the text field
12524 event.preventDefault();
12525 checkFocus.call( this );
12528 // IE doesn't prevent moving focus even with event.preventDefault()
12529 // so we set a flag to know when we should ignore the blur event
12530 // and check (again) if focus moved off of the input.
12531 this.cancelBlur = true;
12532 this._delay(function() {
12533 delete this.cancelBlur;
12534 checkFocus.call( this );
12537 if ( this._start( event ) === false ) {
12541 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
12543 "mouseup .ui-spinner-button": "_stop",
12544 "mouseenter .ui-spinner-button": function( event ) {
12545 // button will add ui-state-active if mouse was down while mouseleave and kept down
12546 if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
12550 if ( this._start( event ) === false ) {
12553 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
12555 // TODO: do we really want to consider this a stop?
12556 // shouldn't we just stop the repeater and wait until mouseup before
12557 // we trigger the stop event?
12558 "mouseleave .ui-spinner-button": "_stop"
12561 _draw: function() {
12562 var uiSpinner = this.uiSpinner = this.element
12563 .addClass( "ui-spinner-input" )
12564 .attr( "autocomplete", "off" )
12565 .wrap( this._uiSpinnerHtml() )
12568 .append( this._buttonHtml() );
12570 this.element.attr( "role", "spinbutton" );
12573 this.buttons = uiSpinner.find( ".ui-spinner-button" )
12574 .attr( "tabIndex", -1 )
12576 .removeClass( "ui-corner-all" );
12578 // IE 6 doesn't understand height: 50% for the buttons
12579 // unless the wrapper has an explicit height
12580 if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) &&
12581 uiSpinner.height() > 0 ) {
12582 uiSpinner.height( uiSpinner.height() );
12585 // disable spinner if element was already disabled
12586 if ( this.options.disabled ) {
12591 _keydown: function( event ) {
12592 var options = this.options,
12593 keyCode = $.ui.keyCode;
12595 switch ( event.keyCode ) {
12597 this._repeat( null, 1, event );
12600 this._repeat( null, -1, event );
12602 case keyCode.PAGE_UP:
12603 this._repeat( null, options.page, event );
12605 case keyCode.PAGE_DOWN:
12606 this._repeat( null, -options.page, event );
12613 _uiSpinnerHtml: function() {
12614 return "<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>";
12617 _buttonHtml: function() {
12619 "<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>" +
12620 "<span class='ui-icon " + this.options.icons.up + "'>▲</span>" +
12622 "<a class='ui-spinner-button ui-spinner-down ui-corner-br'>" +
12623 "<span class='ui-icon " + this.options.icons.down + "'>▼</span>" +
12627 _start: function( event ) {
12628 if ( !this.spinning && this._trigger( "start", event ) === false ) {
12632 if ( !this.counter ) {
12635 this.spinning = true;
12639 _repeat: function( i, steps, event ) {
12642 clearTimeout( this.timer );
12643 this.timer = this._delay(function() {
12644 this._repeat( 40, steps, event );
12647 this._spin( steps * this.options.step, event );
12650 _spin: function( step, event ) {
12651 var value = this.value() || 0;
12653 if ( !this.counter ) {
12657 value = this._adjustValue( value + step * this._increment( this.counter ) );
12659 if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) {
12660 this._value( value );
12665 _increment: function( i ) {
12666 var incremental = this.options.incremental;
12668 if ( incremental ) {
12669 return $.isFunction( incremental ) ?
12671 Math.floor( i * i * i / 50000 - i * i / 500 + 17 * i / 200 + 1 );
12677 _precision: function() {
12678 var precision = this._precisionOf( this.options.step );
12679 if ( this.options.min !== null ) {
12680 precision = Math.max( precision, this._precisionOf( this.options.min ) );
12685 _precisionOf: function( num ) {
12686 var str = num.toString(),
12687 decimal = str.indexOf( "." );
12688 return decimal === -1 ? 0 : str.length - decimal - 1;
12691 _adjustValue: function( value ) {
12692 var base, aboveMin,
12693 options = this.options;
12695 // make sure we're at a valid step
12696 // - find out where we are relative to the base (min or 0)
12697 base = options.min !== null ? options.min : 0;
12698 aboveMin = value - base;
12699 // - round to the nearest step
12700 aboveMin = Math.round(aboveMin / options.step) * options.step;
12701 // - rounding is based on 0, so adjust back to our base
12702 value = base + aboveMin;
12704 // fix precision from bad JS floating point math
12705 value = parseFloat( value.toFixed( this._precision() ) );
12708 if ( options.max !== null && value > options.max) {
12709 return options.max;
12711 if ( options.min !== null && value < options.min ) {
12712 return options.min;
12718 _stop: function( event ) {
12719 if ( !this.spinning ) {
12723 clearTimeout( this.timer );
12724 clearTimeout( this.mousewheelTimer );
12726 this.spinning = false;
12727 this._trigger( "stop", event );
12730 _setOption: function( key, value ) {
12731 if ( key === "culture" || key === "numberFormat" ) {
12732 var prevValue = this._parse( this.element.val() );
12733 this.options[ key ] = value;
12734 this.element.val( this._format( prevValue ) );
12738 if ( key === "max" || key === "min" || key === "step" ) {
12739 if ( typeof value === "string" ) {
12740 value = this._parse( value );
12743 if ( key === "icons" ) {
12744 this.buttons.first().find( ".ui-icon" )
12745 .removeClass( this.options.icons.up )
12746 .addClass( value.up );
12747 this.buttons.last().find( ".ui-icon" )
12748 .removeClass( this.options.icons.down )
12749 .addClass( value.down );
12752 this._super( key, value );
12754 if ( key === "disabled" ) {
12755 this.widget().toggleClass( "ui-state-disabled", !!value );
12756 this.element.prop( "disabled", !!value );
12757 this.buttons.button( value ? "disable" : "enable" );
12761 _setOptions: spinner_modifier(function( options ) {
12762 this._super( options );
12765 _parse: function( val ) {
12766 if ( typeof val === "string" && val !== "" ) {
12767 val = window.Globalize && this.options.numberFormat ?
12768 Globalize.parseFloat( val, 10, this.options.culture ) : +val;
12770 return val === "" || isNaN( val ) ? null : val;
12773 _format: function( value ) {
12774 if ( value === "" ) {
12777 return window.Globalize && this.options.numberFormat ?
12778 Globalize.format( value, this.options.numberFormat, this.options.culture ) :
12782 _refresh: function() {
12783 this.element.attr({
12784 "aria-valuemin": this.options.min,
12785 "aria-valuemax": this.options.max,
12786 // TODO: what should we do with values that can't be parsed?
12787 "aria-valuenow": this._parse( this.element.val() )
12791 isValid: function() {
12792 var value = this.value();
12795 if ( value === null ) {
12799 // if value gets adjusted, it's invalid
12800 return value === this._adjustValue( value );
12803 // update the value without triggering change
12804 _value: function( value, allowAny ) {
12806 if ( value !== "" ) {
12807 parsed = this._parse( value );
12808 if ( parsed !== null ) {
12810 parsed = this._adjustValue( parsed );
12812 value = this._format( parsed );
12815 this.element.val( value );
12819 _destroy: function() {
12821 .removeClass( "ui-spinner-input" )
12822 .prop( "disabled", false )
12823 .removeAttr( "autocomplete" )
12824 .removeAttr( "role" )
12825 .removeAttr( "aria-valuemin" )
12826 .removeAttr( "aria-valuemax" )
12827 .removeAttr( "aria-valuenow" );
12828 this.uiSpinner.replaceWith( this.element );
12831 stepUp: spinner_modifier(function( steps ) {
12832 this._stepUp( steps );
12834 _stepUp: function( steps ) {
12835 if ( this._start() ) {
12836 this._spin( (steps || 1) * this.options.step );
12841 stepDown: spinner_modifier(function( steps ) {
12842 this._stepDown( steps );
12844 _stepDown: function( steps ) {
12845 if ( this._start() ) {
12846 this._spin( (steps || 1) * -this.options.step );
12851 pageUp: spinner_modifier(function( pages ) {
12852 this._stepUp( (pages || 1) * this.options.page );
12855 pageDown: spinner_modifier(function( pages ) {
12856 this._stepDown( (pages || 1) * this.options.page );
12859 value: function( newVal ) {
12860 if ( !arguments.length ) {
12861 return this._parse( this.element.val() );
12863 spinner_modifier( this._value ).call( this, newVal );
12866 widget: function() {
12867 return this.uiSpinner;
12873 * jQuery UI Tabs 1.11.3
12874 * http://jqueryui.com
12876 * Copyright jQuery Foundation and other contributors
12877 * Released under the MIT license.
12878 * http://jquery.org/license
12880 * http://api.jqueryui.com/tabs/
12884 var tabs = $.widget( "ui.tabs", {
12889 collapsible: false,
12891 heightStyle: "content",
12897 beforeActivate: null,
12902 _isLocal: (function() {
12903 var rhash = /#.*$/;
12905 return function( anchor ) {
12906 var anchorUrl, locationUrl;
12909 // IE7 doesn't normalize the href property when set via script (#9317)
12910 anchor = anchor.cloneNode( false );
12912 anchorUrl = anchor.href.replace( rhash, "" );
12913 locationUrl = location.href.replace( rhash, "" );
12915 // decoding may throw an error if the URL isn't UTF-8 (#9518)
12917 anchorUrl = decodeURIComponent( anchorUrl );
12918 } catch ( error ) {}
12920 locationUrl = decodeURIComponent( locationUrl );
12921 } catch ( error ) {}
12923 return anchor.hash.length > 1 && anchorUrl === locationUrl;
12927 _create: function() {
12929 options = this.options;
12931 this.running = false;
12934 .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" )
12935 .toggleClass( "ui-tabs-collapsible", options.collapsible );
12937 this._processTabs();
12938 options.active = this._initialActive();
12940 // Take disabling tabs via class attribute from HTML
12941 // into account and update option properly.
12942 if ( $.isArray( options.disabled ) ) {
12943 options.disabled = $.unique( options.disabled.concat(
12944 $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
12945 return that.tabs.index( li );
12950 // check for length avoids error when initializing empty list
12951 if ( this.options.active !== false && this.anchors.length ) {
12952 this.active = this._findActive( options.active );
12959 if ( this.active.length ) {
12960 this.load( options.active );
12964 _initialActive: function() {
12965 var active = this.options.active,
12966 collapsible = this.options.collapsible,
12967 locationHash = location.hash.substring( 1 );
12969 if ( active === null ) {
12970 // check the fragment identifier in the URL
12971 if ( locationHash ) {
12972 this.tabs.each(function( i, tab ) {
12973 if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
12980 // check for a tab marked active via a class
12981 if ( active === null ) {
12982 active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
12985 // no active tab, set to false
12986 if ( active === null || active === -1 ) {
12987 active = this.tabs.length ? 0 : false;
12991 // handle numbers: negative, out of range
12992 if ( active !== false ) {
12993 active = this.tabs.index( this.tabs.eq( active ) );
12994 if ( active === -1 ) {
12995 active = collapsible ? false : 0;
12999 // don't allow collapsible: false and active: false
13000 if ( !collapsible && active === false && this.anchors.length ) {
13007 _getCreateEventData: function() {
13010 panel: !this.active.length ? $() : this._getPanelForTab( this.active )
13014 _tabKeydown: function( event ) {
13015 var focusedTab = $( this.document[0].activeElement ).closest( "li" ),
13016 selectedIndex = this.tabs.index( focusedTab ),
13017 goingForward = true;
13019 if ( this._handlePageNav( event ) ) {
13023 switch ( event.keyCode ) {
13024 case $.ui.keyCode.RIGHT:
13025 case $.ui.keyCode.DOWN:
13028 case $.ui.keyCode.UP:
13029 case $.ui.keyCode.LEFT:
13030 goingForward = false;
13033 case $.ui.keyCode.END:
13034 selectedIndex = this.anchors.length - 1;
13036 case $.ui.keyCode.HOME:
13039 case $.ui.keyCode.SPACE:
13040 // Activate only, no collapsing
13041 event.preventDefault();
13042 clearTimeout( this.activating );
13043 this._activate( selectedIndex );
13045 case $.ui.keyCode.ENTER:
13046 // Toggle (cancel delayed activation, allow collapsing)
13047 event.preventDefault();
13048 clearTimeout( this.activating );
13049 // Determine if we should collapse or activate
13050 this._activate( selectedIndex === this.options.active ? false : selectedIndex );
13056 // Focus the appropriate tab, based on which key was pressed
13057 event.preventDefault();
13058 clearTimeout( this.activating );
13059 selectedIndex = this._focusNextTab( selectedIndex, goingForward );
13061 // Navigating with control/command key will prevent automatic activation
13062 if ( !event.ctrlKey && !event.metaKey ) {
13064 // Update aria-selected immediately so that AT think the tab is already selected.
13065 // Otherwise AT may confuse the user by stating that they need to activate the tab,
13066 // but the tab will already be activated by the time the announcement finishes.
13067 focusedTab.attr( "aria-selected", "false" );
13068 this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
13070 this.activating = this._delay(function() {
13071 this.option( "active", selectedIndex );
13076 _panelKeydown: function( event ) {
13077 if ( this._handlePageNav( event ) ) {
13081 // Ctrl+up moves focus to the current tab
13082 if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
13083 event.preventDefault();
13084 this.active.focus();
13088 // Alt+page up/down moves focus to the previous/next tab (and activates)
13089 _handlePageNav: function( event ) {
13090 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
13091 this._activate( this._focusNextTab( this.options.active - 1, false ) );
13094 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
13095 this._activate( this._focusNextTab( this.options.active + 1, true ) );
13100 _findNextTab: function( index, goingForward ) {
13101 var lastTabIndex = this.tabs.length - 1;
13103 function constrain() {
13104 if ( index > lastTabIndex ) {
13108 index = lastTabIndex;
13113 while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
13114 index = goingForward ? index + 1 : index - 1;
13120 _focusNextTab: function( index, goingForward ) {
13121 index = this._findNextTab( index, goingForward );
13122 this.tabs.eq( index ).focus();
13126 _setOption: function( key, value ) {
13127 if ( key === "active" ) {
13128 // _activate() will handle invalid values and update this.options
13129 this._activate( value );
13133 if ( key === "disabled" ) {
13134 // don't use the widget factory's disabled handling
13135 this._setupDisabled( value );
13139 this._super( key, value);
13141 if ( key === "collapsible" ) {
13142 this.element.toggleClass( "ui-tabs-collapsible", value );
13143 // Setting collapsible: false while collapsed; open first panel
13144 if ( !value && this.options.active === false ) {
13145 this._activate( 0 );
13149 if ( key === "event" ) {
13150 this._setupEvents( value );
13153 if ( key === "heightStyle" ) {
13154 this._setupHeightStyle( value );
13158 _sanitizeSelector: function( hash ) {
13159 return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
13162 refresh: function() {
13163 var options = this.options,
13164 lis = this.tablist.children( ":has(a[href])" );
13166 // get disabled tabs from class attribute from HTML
13167 // this will get converted to a boolean if needed in _refresh()
13168 options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
13169 return lis.index( tab );
13172 this._processTabs();
13174 // was collapsed or no tabs
13175 if ( options.active === false || !this.anchors.length ) {
13176 options.active = false;
13178 // was active, but active tab is gone
13179 } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
13180 // all remaining tabs are disabled
13181 if ( this.tabs.length === options.disabled.length ) {
13182 options.active = false;
13184 // activate previous tab
13186 this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
13188 // was active, active tab still exists
13190 // make sure active index is correct
13191 options.active = this.tabs.index( this.active );
13197 _refresh: function() {
13198 this._setupDisabled( this.options.disabled );
13199 this._setupEvents( this.options.event );
13200 this._setupHeightStyle( this.options.heightStyle );
13202 this.tabs.not( this.active ).attr({
13203 "aria-selected": "false",
13204 "aria-expanded": "false",
13207 this.panels.not( this._getPanelForTab( this.active ) )
13210 "aria-hidden": "true"
13213 // Make sure one tab is in the tab order
13214 if ( !this.active.length ) {
13215 this.tabs.eq( 0 ).attr( "tabIndex", 0 );
13218 .addClass( "ui-tabs-active ui-state-active" )
13220 "aria-selected": "true",
13221 "aria-expanded": "true",
13224 this._getPanelForTab( this.active )
13227 "aria-hidden": "false"
13232 _processTabs: function() {
13234 prevTabs = this.tabs,
13235 prevAnchors = this.anchors,
13236 prevPanels = this.panels;
13238 this.tablist = this._getList()
13239 .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
13240 .attr( "role", "tablist" )
13242 // Prevent users from focusing disabled tabs via click
13243 .delegate( "> li", "mousedown" + this.eventNamespace, function( event ) {
13244 if ( $( this ).is( ".ui-state-disabled" ) ) {
13245 event.preventDefault();
13250 // Preventing the default action in mousedown doesn't prevent IE
13251 // from focusing the element, so if the anchor gets focused, blur.
13252 // We don't have to worry about focusing the previously focused
13253 // element since clicking on a non-focusable element should focus
13254 // the body anyway.
13255 .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() {
13256 if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
13261 this.tabs = this.tablist.find( "> li:has(a[href])" )
13262 .addClass( "ui-state-default ui-corner-top" )
13268 this.anchors = this.tabs.map(function() {
13269 return $( "a", this )[ 0 ];
13271 .addClass( "ui-tabs-anchor" )
13273 role: "presentation",
13279 this.anchors.each(function( i, anchor ) {
13280 var selector, panel, panelId,
13281 anchorId = $( anchor ).uniqueId().attr( "id" ),
13282 tab = $( anchor ).closest( "li" ),
13283 originalAriaControls = tab.attr( "aria-controls" );
13286 if ( that._isLocal( anchor ) ) {
13287 selector = anchor.hash;
13288 panelId = selector.substring( 1 );
13289 panel = that.element.find( that._sanitizeSelector( selector ) );
13292 // If the tab doesn't already have aria-controls,
13293 // generate an id by using a throw-away element
13294 panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id;
13295 selector = "#" + panelId;
13296 panel = that.element.find( selector );
13297 if ( !panel.length ) {
13298 panel = that._createPanel( panelId );
13299 panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
13301 panel.attr( "aria-live", "polite" );
13304 if ( panel.length) {
13305 that.panels = that.panels.add( panel );
13307 if ( originalAriaControls ) {
13308 tab.data( "ui-tabs-aria-controls", originalAriaControls );
13311 "aria-controls": panelId,
13312 "aria-labelledby": anchorId
13314 panel.attr( "aria-labelledby", anchorId );
13318 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
13319 .attr( "role", "tabpanel" );
13321 // Avoid memory leaks (#10056)
13323 this._off( prevTabs.not( this.tabs ) );
13324 this._off( prevAnchors.not( this.anchors ) );
13325 this._off( prevPanels.not( this.panels ) );
13329 // allow overriding how to find the list for rare usage scenarios (#7715)
13330 _getList: function() {
13331 return this.tablist || this.element.find( "ol,ul" ).eq( 0 );
13334 _createPanel: function( id ) {
13335 return $( "<div>" )
13337 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
13338 .data( "ui-tabs-destroy", true );
13341 _setupDisabled: function( disabled ) {
13342 if ( $.isArray( disabled ) ) {
13343 if ( !disabled.length ) {
13345 } else if ( disabled.length === this.anchors.length ) {
13351 for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) {
13352 if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
13354 .addClass( "ui-state-disabled" )
13355 .attr( "aria-disabled", "true" );
13358 .removeClass( "ui-state-disabled" )
13359 .removeAttr( "aria-disabled" );
13363 this.options.disabled = disabled;
13366 _setupEvents: function( event ) {
13369 $.each( event.split(" "), function( index, eventName ) {
13370 events[ eventName ] = "_eventHandler";
13374 this._off( this.anchors.add( this.tabs ).add( this.panels ) );
13375 // Always prevent the default action, even when disabled
13376 this._on( true, this.anchors, {
13377 click: function( event ) {
13378 event.preventDefault();
13381 this._on( this.anchors, events );
13382 this._on( this.tabs, { keydown: "_tabKeydown" } );
13383 this._on( this.panels, { keydown: "_panelKeydown" } );
13385 this._focusable( this.tabs );
13386 this._hoverable( this.tabs );
13389 _setupHeightStyle: function( heightStyle ) {
13391 parent = this.element.parent();
13393 if ( heightStyle === "fill" ) {
13394 maxHeight = parent.height();
13395 maxHeight -= this.element.outerHeight() - this.element.height();
13397 this.element.siblings( ":visible" ).each(function() {
13398 var elem = $( this ),
13399 position = elem.css( "position" );
13401 if ( position === "absolute" || position === "fixed" ) {
13404 maxHeight -= elem.outerHeight( true );
13407 this.element.children().not( this.panels ).each(function() {
13408 maxHeight -= $( this ).outerHeight( true );
13411 this.panels.each(function() {
13412 $( this ).height( Math.max( 0, maxHeight -
13413 $( this ).innerHeight() + $( this ).height() ) );
13415 .css( "overflow", "auto" );
13416 } else if ( heightStyle === "auto" ) {
13418 this.panels.each(function() {
13419 maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
13420 }).height( maxHeight );
13424 _eventHandler: function( event ) {
13425 var options = this.options,
13426 active = this.active,
13427 anchor = $( event.currentTarget ),
13428 tab = anchor.closest( "li" ),
13429 clickedIsActive = tab[ 0 ] === active[ 0 ],
13430 collapsing = clickedIsActive && options.collapsible,
13431 toShow = collapsing ? $() : this._getPanelForTab( tab ),
13432 toHide = !active.length ? $() : this._getPanelForTab( active ),
13436 newTab: collapsing ? $() : tab,
13440 event.preventDefault();
13442 if ( tab.hasClass( "ui-state-disabled" ) ||
13443 // tab is already loading
13444 tab.hasClass( "ui-tabs-loading" ) ||
13445 // can't switch durning an animation
13447 // click on active header, but not collapsible
13448 ( clickedIsActive && !options.collapsible ) ||
13449 // allow canceling activation
13450 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
13454 options.active = collapsing ? false : this.tabs.index( tab );
13456 this.active = clickedIsActive ? $() : tab;
13461 if ( !toHide.length && !toShow.length ) {
13462 $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
13465 if ( toShow.length ) {
13466 this.load( this.tabs.index( tab ), event );
13468 this._toggle( event, eventData );
13471 // handles show/hide for selecting tabs
13472 _toggle: function( event, eventData ) {
13474 toShow = eventData.newPanel,
13475 toHide = eventData.oldPanel;
13477 this.running = true;
13479 function complete() {
13480 that.running = false;
13481 that._trigger( "activate", event, eventData );
13485 eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" );
13487 if ( toShow.length && that.options.show ) {
13488 that._show( toShow, that.options.show, complete );
13495 // start out by hiding, then showing, then completing
13496 if ( toHide.length && this.options.hide ) {
13497 this._hide( toHide, this.options.hide, function() {
13498 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
13502 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
13507 toHide.attr( "aria-hidden", "true" );
13508 eventData.oldTab.attr({
13509 "aria-selected": "false",
13510 "aria-expanded": "false"
13512 // If we're switching tabs, remove the old tab from the tab order.
13513 // If we're opening from collapsed state, remove the previous tab from the tab order.
13514 // If we're collapsing, then keep the collapsing tab in the tab order.
13515 if ( toShow.length && toHide.length ) {
13516 eventData.oldTab.attr( "tabIndex", -1 );
13517 } else if ( toShow.length ) {
13518 this.tabs.filter(function() {
13519 return $( this ).attr( "tabIndex" ) === 0;
13521 .attr( "tabIndex", -1 );
13524 toShow.attr( "aria-hidden", "false" );
13525 eventData.newTab.attr({
13526 "aria-selected": "true",
13527 "aria-expanded": "true",
13532 _activate: function( index ) {
13534 active = this._findActive( index );
13536 // trying to activate the already active panel
13537 if ( active[ 0 ] === this.active[ 0 ] ) {
13541 // trying to collapse, simulate a click on the current active header
13542 if ( !active.length ) {
13543 active = this.active;
13546 anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
13547 this._eventHandler({
13549 currentTarget: anchor,
13550 preventDefault: $.noop
13554 _findActive: function( index ) {
13555 return index === false ? $() : this.tabs.eq( index );
13558 _getIndex: function( index ) {
13559 // meta-function to give users option to provide a href string instead of a numerical index.
13560 if ( typeof index === "string" ) {
13561 index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) );
13567 _destroy: function() {
13572 this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" );
13575 .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
13576 .removeAttr( "role" );
13579 .removeClass( "ui-tabs-anchor" )
13580 .removeAttr( "role" )
13581 .removeAttr( "tabIndex" )
13584 this.tablist.unbind( this.eventNamespace );
13586 this.tabs.add( this.panels ).each(function() {
13587 if ( $.data( this, "ui-tabs-destroy" ) ) {
13588 $( this ).remove();
13591 .removeClass( "ui-state-default ui-state-active ui-state-disabled " +
13592 "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" )
13593 .removeAttr( "tabIndex" )
13594 .removeAttr( "aria-live" )
13595 .removeAttr( "aria-busy" )
13596 .removeAttr( "aria-selected" )
13597 .removeAttr( "aria-labelledby" )
13598 .removeAttr( "aria-hidden" )
13599 .removeAttr( "aria-expanded" )
13600 .removeAttr( "role" );
13604 this.tabs.each(function() {
13605 var li = $( this ),
13606 prev = li.data( "ui-tabs-aria-controls" );
13609 .attr( "aria-controls", prev )
13610 .removeData( "ui-tabs-aria-controls" );
13612 li.removeAttr( "aria-controls" );
13616 this.panels.show();
13618 if ( this.options.heightStyle !== "content" ) {
13619 this.panels.css( "height", "" );
13623 enable: function( index ) {
13624 var disabled = this.options.disabled;
13625 if ( disabled === false ) {
13629 if ( index === undefined ) {
13632 index = this._getIndex( index );
13633 if ( $.isArray( disabled ) ) {
13634 disabled = $.map( disabled, function( num ) {
13635 return num !== index ? num : null;
13638 disabled = $.map( this.tabs, function( li, num ) {
13639 return num !== index ? num : null;
13643 this._setupDisabled( disabled );
13646 disable: function( index ) {
13647 var disabled = this.options.disabled;
13648 if ( disabled === true ) {
13652 if ( index === undefined ) {
13655 index = this._getIndex( index );
13656 if ( $.inArray( index, disabled ) !== -1 ) {
13659 if ( $.isArray( disabled ) ) {
13660 disabled = $.merge( [ index ], disabled ).sort();
13662 disabled = [ index ];
13665 this._setupDisabled( disabled );
13668 load: function( index, event ) {
13669 index = this._getIndex( index );
13671 tab = this.tabs.eq( index ),
13672 anchor = tab.find( ".ui-tabs-anchor" ),
13673 panel = this._getPanelForTab( tab ),
13680 if ( this._isLocal( anchor[ 0 ] ) ) {
13684 this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
13686 // support: jQuery <1.8
13687 // jQuery <1.8 returns false if the request is canceled in beforeSend,
13688 // but as of 1.8, $.ajax() always returns a jqXHR object.
13689 if ( this.xhr && this.xhr.statusText !== "canceled" ) {
13690 tab.addClass( "ui-tabs-loading" );
13691 panel.attr( "aria-busy", "true" );
13694 .success(function( response ) {
13695 // support: jQuery <1.8
13696 // http://bugs.jquery.com/ticket/11778
13697 setTimeout(function() {
13698 panel.html( response );
13699 that._trigger( "load", event, eventData );
13702 .complete(function( jqXHR, status ) {
13703 // support: jQuery <1.8
13704 // http://bugs.jquery.com/ticket/11778
13705 setTimeout(function() {
13706 if ( status === "abort" ) {
13707 that.panels.stop( false, true );
13710 tab.removeClass( "ui-tabs-loading" );
13711 panel.removeAttr( "aria-busy" );
13713 if ( jqXHR === that.xhr ) {
13721 _ajaxSettings: function( anchor, event, eventData ) {
13724 url: anchor.attr( "href" ),
13725 beforeSend: function( jqXHR, settings ) {
13726 return that._trigger( "beforeLoad", event,
13727 $.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) );
13732 _getPanelForTab: function( tab ) {
13733 var id = $( tab ).attr( "aria-controls" );
13734 return this.element.find( this._sanitizeSelector( "#" + id ) );
13740 * jQuery UI Tooltip 1.11.3
13741 * http://jqueryui.com
13743 * Copyright jQuery Foundation and other contributors
13744 * Released under the MIT license.
13745 * http://jquery.org/license
13747 * http://api.jqueryui.com/tooltip/
13751 var tooltip = $.widget( "ui.tooltip", {
13754 content: function() {
13755 // support: IE<9, Opera in jQuery <1.7
13756 // .text() can't accept undefined, so coerce to a string
13757 var title = $( this ).attr( "title" ) || "";
13758 // Escape title, since we're going from an attribute to raw HTML
13759 return $( "<a>" ).text( title ).html();
13762 // Disabled elements have inconsistent behavior across browsers (#8661)
13763 items: "[title]:not([disabled])",
13767 collision: "flipfit flip"
13770 tooltipClass: null,
13778 _addDescribedBy: function( elem, id ) {
13779 var describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ );
13780 describedby.push( id );
13782 .data( "ui-tooltip-id", id )
13783 .attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
13786 _removeDescribedBy: function( elem ) {
13787 var id = elem.data( "ui-tooltip-id" ),
13788 describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ),
13789 index = $.inArray( id, describedby );
13791 if ( index !== -1 ) {
13792 describedby.splice( index, 1 );
13795 elem.removeData( "ui-tooltip-id" );
13796 describedby = $.trim( describedby.join( " " ) );
13797 if ( describedby ) {
13798 elem.attr( "aria-describedby", describedby );
13800 elem.removeAttr( "aria-describedby" );
13804 _create: function() {
13810 // IDs of generated tooltips, needed for destroy
13811 this.tooltips = {};
13813 // IDs of parent tooltips where we removed the title attribute
13816 if ( this.options.disabled ) {
13820 // Append the aria-live region so tooltips announce correctly
13821 this.liveRegion = $( "<div>" )
13824 "aria-live": "assertive",
13825 "aria-relevant": "additions"
13827 .addClass( "ui-helper-hidden-accessible" )
13828 .appendTo( this.document[ 0 ].body );
13831 _setOption: function( key, value ) {
13834 if ( key === "disabled" ) {
13835 this[ value ? "_disable" : "_enable" ]();
13836 this.options[ key ] = value;
13837 // disable element style changes
13841 this._super( key, value );
13843 if ( key === "content" ) {
13844 $.each( this.tooltips, function( id, tooltipData ) {
13845 that._updateContent( tooltipData.element );
13850 _disable: function() {
13853 // close open tooltips
13854 $.each( this.tooltips, function( id, tooltipData ) {
13855 var event = $.Event( "blur" );
13856 event.target = event.currentTarget = tooltipData.element[ 0 ];
13857 that.close( event, true );
13860 // remove title attributes to prevent native tooltips
13861 this.element.find( this.options.items ).addBack().each(function() {
13862 var element = $( this );
13863 if ( element.is( "[title]" ) ) {
13865 .data( "ui-tooltip-title", element.attr( "title" ) )
13866 .removeAttr( "title" );
13871 _enable: function() {
13872 // restore title attributes
13873 this.element.find( this.options.items ).addBack().each(function() {
13874 var element = $( this );
13875 if ( element.data( "ui-tooltip-title" ) ) {
13876 element.attr( "title", element.data( "ui-tooltip-title" ) );
13881 open: function( event ) {
13883 target = $( event ? event.target : this.element )
13884 // we need closest here due to mouseover bubbling,
13885 // but always pointing at the same event target
13886 .closest( this.options.items );
13888 // No element to show a tooltip for or the tooltip is already open
13889 if ( !target.length || target.data( "ui-tooltip-id" ) ) {
13893 if ( target.attr( "title" ) ) {
13894 target.data( "ui-tooltip-title", target.attr( "title" ) );
13897 target.data( "ui-tooltip-open", true );
13899 // kill parent tooltips, custom or native, for hover
13900 if ( event && event.type === "mouseover" ) {
13901 target.parents().each(function() {
13902 var parent = $( this ),
13904 if ( parent.data( "ui-tooltip-open" ) ) {
13905 blurEvent = $.Event( "blur" );
13906 blurEvent.target = blurEvent.currentTarget = this;
13907 that.close( blurEvent, true );
13909 if ( parent.attr( "title" ) ) {
13911 that.parents[ this.id ] = {
13913 title: parent.attr( "title" )
13915 parent.attr( "title", "" );
13920 this._updateContent( target, event );
13923 _updateContent: function( target, event ) {
13925 contentOption = this.options.content,
13927 eventType = event ? event.type : null;
13929 if ( typeof contentOption === "string" ) {
13930 return this._open( event, target, contentOption );
13933 content = contentOption.call( target[0], function( response ) {
13934 // ignore async response if tooltip was closed already
13935 if ( !target.data( "ui-tooltip-open" ) ) {
13938 // IE may instantly serve a cached response for ajax requests
13939 // delay this call to _open so the other call to _open runs first
13940 that._delay(function() {
13941 // jQuery creates a special event for focusin when it doesn't
13942 // exist natively. To improve performance, the native event
13943 // object is reused and the type is changed. Therefore, we can't
13944 // rely on the type being correct after the event finished
13945 // bubbling, so we set it back to the previous value. (#8740)
13947 event.type = eventType;
13949 this._open( event, target, response );
13953 this._open( event, target, content );
13957 _open: function( event, target, content ) {
13958 var tooltipData, tooltip, events, delayedShow, a11yContent,
13959 positionOption = $.extend( {}, this.options.position );
13965 // Content can be updated multiple times. If the tooltip already
13966 // exists, then just update the content and bail.
13967 tooltipData = this._find( target );
13968 if ( tooltipData ) {
13969 tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content );
13973 // if we have a title, clear it to prevent the native tooltip
13974 // we have to check first to avoid defining a title if none exists
13975 // (we don't want to cause an element to start matching [title])
13977 // We use removeAttr only for key events, to allow IE to export the correct
13978 // accessible attributes. For mouse events, set to empty string to avoid
13979 // native tooltip showing up (happens only when removing inside mouseover).
13980 if ( target.is( "[title]" ) ) {
13981 if ( event && event.type === "mouseover" ) {
13982 target.attr( "title", "" );
13984 target.removeAttr( "title" );
13988 tooltipData = this._tooltip( target );
13989 tooltip = tooltipData.tooltip;
13990 this._addDescribedBy( target, tooltip.attr( "id" ) );
13991 tooltip.find( ".ui-tooltip-content" ).html( content );
13993 // Support: Voiceover on OS X, JAWS on IE <= 9
13994 // JAWS announces deletions even when aria-relevant="additions"
13995 // Voiceover will sometimes re-read the entire log region's contents from the beginning
13996 this.liveRegion.children().hide();
13997 if ( content.clone ) {
13998 a11yContent = content.clone();
13999 a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" );
14001 a11yContent = content;
14003 $( "<div>" ).html( a11yContent ).appendTo( this.liveRegion );
14005 function position( event ) {
14006 positionOption.of = event;
14007 if ( tooltip.is( ":hidden" ) ) {
14010 tooltip.position( positionOption );
14012 if ( this.options.track && event && /^mouse/.test( event.type ) ) {
14013 this._on( this.document, {
14014 mousemove: position
14016 // trigger once to override element-relative positioning
14019 tooltip.position( $.extend({
14021 }, this.options.position ) );
14026 this._show( tooltip, this.options.show );
14027 // Handle tracking tooltips that are shown with a delay (#8644). As soon
14028 // as the tooltip is visible, position the tooltip using the most recent
14030 if ( this.options.show && this.options.show.delay ) {
14031 delayedShow = this.delayedShow = setInterval(function() {
14032 if ( tooltip.is( ":visible" ) ) {
14033 position( positionOption.of );
14034 clearInterval( delayedShow );
14036 }, $.fx.interval );
14039 this._trigger( "open", event, { tooltip: tooltip } );
14042 keyup: function( event ) {
14043 if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
14044 var fakeEvent = $.Event(event);
14045 fakeEvent.currentTarget = target[0];
14046 this.close( fakeEvent, true );
14051 // Only bind remove handler for delegated targets. Non-delegated
14052 // tooltips will handle this in destroy.
14053 if ( target[ 0 ] !== this.element[ 0 ] ) {
14054 events.remove = function() {
14055 this._removeTooltip( tooltip );
14059 if ( !event || event.type === "mouseover" ) {
14060 events.mouseleave = "close";
14062 if ( !event || event.type === "focusin" ) {
14063 events.focusout = "close";
14065 this._on( true, target, events );
14068 close: function( event ) {
14071 target = $( event ? event.currentTarget : this.element ),
14072 tooltipData = this._find( target );
14074 // The tooltip may already be closed
14075 if ( !tooltipData ) {
14079 tooltip = tooltipData.tooltip;
14081 // disabling closes the tooltip, so we need to track when we're closing
14082 // to avoid an infinite loop in case the tooltip becomes disabled on close
14083 if ( tooltipData.closing ) {
14087 // Clear the interval for delayed tracking tooltips
14088 clearInterval( this.delayedShow );
14090 // only set title if we had one before (see comment in _open())
14091 // If the title attribute has changed since open(), don't restore
14092 if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) {
14093 target.attr( "title", target.data( "ui-tooltip-title" ) );
14096 this._removeDescribedBy( target );
14098 tooltipData.hiding = true;
14099 tooltip.stop( true );
14100 this._hide( tooltip, this.options.hide, function() {
14101 that._removeTooltip( $( this ) );
14104 target.removeData( "ui-tooltip-open" );
14105 this._off( target, "mouseleave focusout keyup" );
14107 // Remove 'remove' binding only on delegated targets
14108 if ( target[ 0 ] !== this.element[ 0 ] ) {
14109 this._off( target, "remove" );
14111 this._off( this.document, "mousemove" );
14113 if ( event && event.type === "mouseleave" ) {
14114 $.each( this.parents, function( id, parent ) {
14115 $( parent.element ).attr( "title", parent.title );
14116 delete that.parents[ id ];
14120 tooltipData.closing = true;
14121 this._trigger( "close", event, { tooltip: tooltip } );
14122 if ( !tooltipData.hiding ) {
14123 tooltipData.closing = false;
14127 _tooltip: function( element ) {
14128 var tooltip = $( "<div>" )
14129 .attr( "role", "tooltip" )
14130 .addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " +
14131 ( this.options.tooltipClass || "" ) ),
14132 id = tooltip.uniqueId().attr( "id" );
14135 .addClass( "ui-tooltip-content" )
14136 .appendTo( tooltip );
14138 tooltip.appendTo( this.document[0].body );
14140 return this.tooltips[ id ] = {
14146 _find: function( target ) {
14147 var id = target.data( "ui-tooltip-id" );
14148 return id ? this.tooltips[ id ] : null;
14151 _removeTooltip: function( tooltip ) {
14153 delete this.tooltips[ tooltip.attr( "id" ) ];
14156 _destroy: function() {
14159 // close open tooltips
14160 $.each( this.tooltips, function( id, tooltipData ) {
14161 // Delegate to close method to handle common cleanup
14162 var event = $.Event( "blur" ),
14163 element = tooltipData.element;
14164 event.target = event.currentTarget = element[ 0 ];
14165 that.close( event, true );
14167 // Remove immediately; destroying an open tooltip doesn't use the
14169 $( "#" + id ).remove();
14171 // Restore the title
14172 if ( element.data( "ui-tooltip-title" ) ) {
14173 // If the title attribute has changed since open(), don't restore
14174 if ( !element.attr( "title" ) ) {
14175 element.attr( "title", element.data( "ui-tooltip-title" ) );
14177 element.removeData( "ui-tooltip-title" );
14180 this.liveRegion.remove();
14186 * jQuery UI Effects 1.11.3
14187 * http://jqueryui.com
14189 * Copyright jQuery Foundation and other contributors
14190 * Released under the MIT license.
14191 * http://jquery.org/license
14193 * http://api.jqueryui.com/category/effects-core/
14197 var dataSpace = "ui-effects-",
14199 // Create a local jQuery because jQuery Color relies on it and the
14200 // global may not exist with AMD and a custom build (#10199)
14208 * jQuery Color Animations v2.1.2
14209 * https://github.com/jquery/jquery-color
14211 * Copyright 2014 jQuery Foundation and other contributors
14212 * Released under the MIT license.
14213 * http://jquery.org/license
14215 * Date: Wed Jan 16 08:47:09 2013 -0600
14217 (function( jQuery, undefined ) {
14219 var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
14221 // plusequals test for += 100 -= 100
14222 rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
14223 // a set of RE's that can match strings and generate color tuples.
14224 stringParsers = [ {
14225 re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
14226 parse: function( execResult ) {
14235 re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
14236 parse: function( execResult ) {
14238 execResult[ 1 ] * 2.55,
14239 execResult[ 2 ] * 2.55,
14240 execResult[ 3 ] * 2.55,
14245 // this regex ignores A-F because it's compared against an already lowercased string
14246 re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
14247 parse: function( execResult ) {
14249 parseInt( execResult[ 1 ], 16 ),
14250 parseInt( execResult[ 2 ], 16 ),
14251 parseInt( execResult[ 3 ], 16 )
14255 // this regex ignores A-F because it's compared against an already lowercased string
14256 re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
14257 parse: function( execResult ) {
14259 parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
14260 parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
14261 parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
14265 re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
14267 parse: function( execResult ) {
14270 execResult[ 2 ] / 100,
14271 execResult[ 3 ] / 100,
14278 color = jQuery.Color = function( color, green, blue, alpha ) {
14279 return new jQuery.Color.fn.parse( color, green, blue, alpha );
14329 support = color.support = {},
14331 // element for support tests
14332 supportElem = jQuery( "<p>" )[ 0 ],
14334 // colors = jQuery.Color.names
14337 // local aliases of functions called often
14338 each = jQuery.each;
14340 // determine rgba support immediately
14341 supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
14342 support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
14344 // define cache name and alpha properties
14345 // for rgba and hsla spaces
14346 each( spaces, function( spaceName, space ) {
14347 space.cache = "_" + spaceName;
14348 space.props.alpha = {
14355 function clamp( value, prop, allowEmpty ) {
14356 var type = propTypes[ prop.type ] || {};
14358 if ( value == null ) {
14359 return (allowEmpty || !prop.def) ? null : prop.def;
14362 // ~~ is an short way of doing floor for positive numbers
14363 value = type.floor ? ~~value : parseFloat( value );
14365 // IE will pass in empty strings as value for alpha,
14366 // which will hit this case
14367 if ( isNaN( value ) ) {
14372 // we add mod before modding to make sure that negatives values
14373 // get converted properly: -10 -> 350
14374 return (value + type.mod) % type.mod;
14377 // for now all property types without mod have min and max
14378 return 0 > value ? 0 : type.max < value ? type.max : value;
14381 function stringParse( string ) {
14382 var inst = color(),
14383 rgba = inst._rgba = [];
14385 string = string.toLowerCase();
14387 each( stringParsers, function( i, parser ) {
14389 match = parser.re.exec( string ),
14390 values = match && parser.parse( match ),
14391 spaceName = parser.space || "rgba";
14394 parsed = inst[ spaceName ]( values );
14396 // if this was an rgba parse the assignment might happen twice
14398 inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
14399 rgba = inst._rgba = parsed._rgba;
14401 // exit each( stringParsers ) here because we matched
14406 // Found a stringParser that handled it
14407 if ( rgba.length ) {
14409 // if this came from a parsed string, force "transparent" when alpha is 0
14410 // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
14411 if ( rgba.join() === "0,0,0,0" ) {
14412 jQuery.extend( rgba, colors.transparent );
14418 return colors[ string ];
14421 color.fn = jQuery.extend( color.prototype, {
14422 parse: function( red, green, blue, alpha ) {
14423 if ( red === undefined ) {
14424 this._rgba = [ null, null, null, null ];
14427 if ( red.jquery || red.nodeType ) {
14428 red = jQuery( red ).css( green );
14433 type = jQuery.type( red ),
14434 rgba = this._rgba = [];
14436 // more than 1 argument specified - assume ( red, green, blue, alpha )
14437 if ( green !== undefined ) {
14438 red = [ red, green, blue, alpha ];
14442 if ( type === "string" ) {
14443 return this.parse( stringParse( red ) || colors._default );
14446 if ( type === "array" ) {
14447 each( spaces.rgba.props, function( key, prop ) {
14448 rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
14453 if ( type === "object" ) {
14454 if ( red instanceof color ) {
14455 each( spaces, function( spaceName, space ) {
14456 if ( red[ space.cache ] ) {
14457 inst[ space.cache ] = red[ space.cache ].slice();
14461 each( spaces, function( spaceName, space ) {
14462 var cache = space.cache;
14463 each( space.props, function( key, prop ) {
14465 // if the cache doesn't exist, and we know how to convert
14466 if ( !inst[ cache ] && space.to ) {
14468 // if the value was null, we don't need to copy it
14469 // if the key was alpha, we don't need to copy it either
14470 if ( key === "alpha" || red[ key ] == null ) {
14473 inst[ cache ] = space.to( inst._rgba );
14476 // this is the only case where we allow nulls for ALL properties.
14477 // call clamp with alwaysAllowEmpty
14478 inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
14481 // everything defined but alpha?
14482 if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
14483 // use the default of 1
14484 inst[ cache ][ 3 ] = 1;
14485 if ( space.from ) {
14486 inst._rgba = space.from( inst[ cache ] );
14494 is: function( compare ) {
14495 var is = color( compare ),
14499 each( spaces, function( _, space ) {
14501 isCache = is[ space.cache ];
14503 localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
14504 each( space.props, function( _, prop ) {
14505 if ( isCache[ prop.idx ] != null ) {
14506 same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
14515 _space: function() {
14518 each( spaces, function( spaceName, space ) {
14519 if ( inst[ space.cache ] ) {
14520 used.push( spaceName );
14525 transition: function( other, distance ) {
14526 var end = color( other ),
14527 spaceName = end._space(),
14528 space = spaces[ spaceName ],
14529 startColor = this.alpha() === 0 ? color( "transparent" ) : this,
14530 start = startColor[ space.cache ] || space.to( startColor._rgba ),
14531 result = start.slice();
14533 end = end[ space.cache ];
14534 each( space.props, function( key, prop ) {
14535 var index = prop.idx,
14536 startValue = start[ index ],
14537 endValue = end[ index ],
14538 type = propTypes[ prop.type ] || {};
14540 // if null, don't override start value
14541 if ( endValue === null ) {
14544 // if null - use end
14545 if ( startValue === null ) {
14546 result[ index ] = endValue;
14549 if ( endValue - startValue > type.mod / 2 ) {
14550 startValue += type.mod;
14551 } else if ( startValue - endValue > type.mod / 2 ) {
14552 startValue -= type.mod;
14555 result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
14558 return this[ spaceName ]( result );
14560 blend: function( opaque ) {
14561 // if we are already opaque - return ourself
14562 if ( this._rgba[ 3 ] === 1 ) {
14566 var rgb = this._rgba.slice(),
14568 blend = color( opaque )._rgba;
14570 return color( jQuery.map( rgb, function( v, i ) {
14571 return ( 1 - a ) * blend[ i ] + a * v;
14574 toRgbaString: function() {
14575 var prefix = "rgba(",
14576 rgba = jQuery.map( this._rgba, function( v, i ) {
14577 return v == null ? ( i > 2 ? 1 : 0 ) : v;
14580 if ( rgba[ 3 ] === 1 ) {
14585 return prefix + rgba.join() + ")";
14587 toHslaString: function() {
14588 var prefix = "hsla(",
14589 hsla = jQuery.map( this.hsla(), function( v, i ) {
14595 if ( i && i < 3 ) {
14596 v = Math.round( v * 100 ) + "%";
14601 if ( hsla[ 3 ] === 1 ) {
14605 return prefix + hsla.join() + ")";
14607 toHexString: function( includeAlpha ) {
14608 var rgba = this._rgba.slice(),
14609 alpha = rgba.pop();
14611 if ( includeAlpha ) {
14612 rgba.push( ~~( alpha * 255 ) );
14615 return "#" + jQuery.map( rgba, function( v ) {
14617 // default to 0 when nulls exist
14618 v = ( v || 0 ).toString( 16 );
14619 return v.length === 1 ? "0" + v : v;
14622 toString: function() {
14623 return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
14626 color.fn.parse.prototype = color.fn;
14628 // hsla conversions adapted from:
14629 // https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
14631 function hue2rgb( p, q, h ) {
14634 return p + ( q - p ) * h * 6;
14640 return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6;
14645 spaces.hsla.to = function( rgba ) {
14646 if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
14647 return [ null, null, null, rgba[ 3 ] ];
14649 var r = rgba[ 0 ] / 255,
14650 g = rgba[ 1 ] / 255,
14651 b = rgba[ 2 ] / 255,
14653 max = Math.max( r, g, b ),
14654 min = Math.min( r, g, b ),
14660 if ( min === max ) {
14662 } else if ( r === max ) {
14663 h = ( 60 * ( g - b ) / diff ) + 360;
14664 } else if ( g === max ) {
14665 h = ( 60 * ( b - r ) / diff ) + 120;
14667 h = ( 60 * ( r - g ) / diff ) + 240;
14670 // chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
14671 // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
14672 if ( diff === 0 ) {
14674 } else if ( l <= 0.5 ) {
14677 s = diff / ( 2 - add );
14679 return [ Math.round(h) % 360, s, l, a == null ? 1 : a ];
14682 spaces.hsla.from = function( hsla ) {
14683 if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
14684 return [ null, null, null, hsla[ 3 ] ];
14686 var h = hsla[ 0 ] / 360,
14690 q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
14694 Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
14695 Math.round( hue2rgb( p, q, h ) * 255 ),
14696 Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
14701 each( spaces, function( spaceName, space ) {
14702 var props = space.props,
14703 cache = space.cache,
14707 // makes rgba() and hsla()
14708 color.fn[ spaceName ] = function( value ) {
14710 // generate a cache for this space if it doesn't exist
14711 if ( to && !this[ cache ] ) {
14712 this[ cache ] = to( this._rgba );
14714 if ( value === undefined ) {
14715 return this[ cache ].slice();
14719 type = jQuery.type( value ),
14720 arr = ( type === "array" || type === "object" ) ? value : arguments,
14721 local = this[ cache ].slice();
14723 each( props, function( key, prop ) {
14724 var val = arr[ type === "object" ? key : prop.idx ];
14725 if ( val == null ) {
14726 val = local[ prop.idx ];
14728 local[ prop.idx ] = clamp( val, prop );
14732 ret = color( from( local ) );
14733 ret[ cache ] = local;
14736 return color( local );
14740 // makes red() green() blue() alpha() hue() saturation() lightness()
14741 each( props, function( key, prop ) {
14742 // alpha is included in more than one space
14743 if ( color.fn[ key ] ) {
14746 color.fn[ key ] = function( value ) {
14747 var vtype = jQuery.type( value ),
14748 fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
14749 local = this[ fn ](),
14750 cur = local[ prop.idx ],
14753 if ( vtype === "undefined" ) {
14757 if ( vtype === "function" ) {
14758 value = value.call( this, cur );
14759 vtype = jQuery.type( value );
14761 if ( value == null && prop.empty ) {
14764 if ( vtype === "string" ) {
14765 match = rplusequals.exec( value );
14767 value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
14770 local[ prop.idx ] = value;
14771 return this[ fn ]( local );
14776 // add cssHook and .fx.step function for each named hook.
14777 // accept a space separated string of properties
14778 color.hook = function( hook ) {
14779 var hooks = hook.split( " " );
14780 each( hooks, function( i, hook ) {
14781 jQuery.cssHooks[ hook ] = {
14782 set: function( elem, value ) {
14783 var parsed, curElem,
14784 backgroundColor = "";
14786 if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) {
14787 value = color( parsed || value );
14788 if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
14789 curElem = hook === "backgroundColor" ? elem.parentNode : elem;
14791 (backgroundColor === "" || backgroundColor === "transparent") &&
14792 curElem && curElem.style
14795 backgroundColor = jQuery.css( curElem, "backgroundColor" );
14796 curElem = curElem.parentNode;
14801 value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
14806 value = value.toRgbaString();
14809 elem.style[ hook ] = value;
14811 // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit'
14815 jQuery.fx.step[ hook ] = function( fx ) {
14816 if ( !fx.colorInit ) {
14817 fx.start = color( fx.elem, hook );
14818 fx.end = color( fx.end );
14819 fx.colorInit = true;
14821 jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
14827 color.hook( stepHooks );
14829 jQuery.cssHooks.borderColor = {
14830 expand: function( value ) {
14833 each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
14834 expanded[ "border" + part + "Color" ] = value;
14840 // Basic color names only.
14841 // Usage of any of the other color names requires adding yourself or including
14842 // jquery.color.svg-names.js.
14843 colors = jQuery.Color.names = {
14844 // 4.1. Basic color keywords
14848 fuchsia: "#ff00ff",
14862 // 4.2.3. "transparent" color keyword
14863 transparent: [ null, null, null, 0 ],
14865 _default: "#ffffff"
14870 /******************************************************************************/
14871 /****************************** CLASS ANIMATIONS ******************************/
14872 /******************************************************************************/
14875 var classAnimationActions = [ "add", "remove", "toggle" ],
14876 shorthandStyles = {
14888 $.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) {
14889 $.fx.step[ prop ] = function( fx ) {
14890 if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
14891 jQuery.style( fx.elem, prop, fx.end );
14897 function getElementStyles( elem ) {
14899 style = elem.ownerDocument.defaultView ?
14900 elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :
14904 if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
14905 len = style.length;
14907 key = style[ len ];
14908 if ( typeof style[ key ] === "string" ) {
14909 styles[ $.camelCase( key ) ] = style[ key ];
14912 // support: Opera, IE <9
14914 for ( key in style ) {
14915 if ( typeof style[ key ] === "string" ) {
14916 styles[ key ] = style[ key ];
14924 function styleDifference( oldStyle, newStyle ) {
14928 for ( name in newStyle ) {
14929 value = newStyle[ name ];
14930 if ( oldStyle[ name ] !== value ) {
14931 if ( !shorthandStyles[ name ] ) {
14932 if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
14933 diff[ name ] = value;
14942 // support: jQuery <1.8
14943 if ( !$.fn.addBack ) {
14944 $.fn.addBack = function( selector ) {
14945 return this.add( selector == null ?
14946 this.prevObject : this.prevObject.filter( selector )
14951 $.effects.animateClass = function( value, duration, easing, callback ) {
14952 var o = $.speed( duration, easing, callback );
14954 return this.queue( function() {
14955 var animated = $( this ),
14956 baseClass = animated.attr( "class" ) || "",
14958 allAnimations = o.children ? animated.find( "*" ).addBack() : animated;
14960 // map the animated objects to store the original styles.
14961 allAnimations = allAnimations.map(function() {
14962 var el = $( this );
14965 start: getElementStyles( this )
14969 // apply class change
14970 applyClassChange = function() {
14971 $.each( classAnimationActions, function(i, action) {
14972 if ( value[ action ] ) {
14973 animated[ action + "Class" ]( value[ action ] );
14977 applyClassChange();
14979 // map all animated objects again - calculate new styles and diff
14980 allAnimations = allAnimations.map(function() {
14981 this.end = getElementStyles( this.el[ 0 ] );
14982 this.diff = styleDifference( this.start, this.end );
14986 // apply original class
14987 animated.attr( "class", baseClass );
14989 // map all animated objects again - this time collecting a promise
14990 allAnimations = allAnimations.map(function() {
14991 var styleInfo = this,
14992 dfd = $.Deferred(),
14993 opts = $.extend({}, o, {
14995 complete: function() {
14996 dfd.resolve( styleInfo );
15000 this.el.animate( this.diff, opts );
15001 return dfd.promise();
15004 // once all animations have completed:
15005 $.when.apply( $, allAnimations.get() ).done(function() {
15007 // set the final class
15008 applyClassChange();
15010 // for each animated element,
15011 // clear all css properties that were animated
15012 $.each( arguments, function() {
15014 $.each( this.diff, function(key) {
15019 // this is guarnteed to be there if you use jQuery.speed()
15020 // it also handles dequeuing the next anim...
15021 o.complete.call( animated[ 0 ] );
15027 addClass: (function( orig ) {
15028 return function( classNames, speed, easing, callback ) {
15030 $.effects.animateClass.call( this,
15031 { add: classNames }, speed, easing, callback ) :
15032 orig.apply( this, arguments );
15034 })( $.fn.addClass ),
15036 removeClass: (function( orig ) {
15037 return function( classNames, speed, easing, callback ) {
15038 return arguments.length > 1 ?
15039 $.effects.animateClass.call( this,
15040 { remove: classNames }, speed, easing, callback ) :
15041 orig.apply( this, arguments );
15043 })( $.fn.removeClass ),
15045 toggleClass: (function( orig ) {
15046 return function( classNames, force, speed, easing, callback ) {
15047 if ( typeof force === "boolean" || force === undefined ) {
15049 // without speed parameter
15050 return orig.apply( this, arguments );
15052 return $.effects.animateClass.call( this,
15053 (force ? { add: classNames } : { remove: classNames }),
15054 speed, easing, callback );
15057 // without force parameter
15058 return $.effects.animateClass.call( this,
15059 { toggle: classNames }, force, speed, easing );
15062 })( $.fn.toggleClass ),
15064 switchClass: function( remove, add, speed, easing, callback) {
15065 return $.effects.animateClass.call( this, {
15068 }, speed, easing, callback );
15074 /******************************************************************************/
15075 /*********************************** EFFECTS **********************************/
15076 /******************************************************************************/
15080 $.extend( $.effects, {
15083 // Saves a set of properties in a data storage
15084 save: function( element, set ) {
15085 for ( var i = 0; i < set.length; i++ ) {
15086 if ( set[ i ] !== null ) {
15087 element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
15092 // Restores a set of previously saved properties from a data storage
15093 restore: function( element, set ) {
15095 for ( i = 0; i < set.length; i++ ) {
15096 if ( set[ i ] !== null ) {
15097 val = element.data( dataSpace + set[ i ] );
15098 // support: jQuery 1.6.2
15099 // http://bugs.jquery.com/ticket/9917
15100 // jQuery 1.6.2 incorrectly returns undefined for any falsy value.
15101 // We can't differentiate between "" and 0 here, so we just assume
15102 // empty string since it's likely to be a more common value...
15103 if ( val === undefined ) {
15106 element.css( set[ i ], val );
15111 setMode: function( el, mode ) {
15112 if (mode === "toggle") {
15113 mode = el.is( ":hidden" ) ? "show" : "hide";
15118 // Translates a [top,left] array into a baseline value
15119 // this should be a little more flexible in the future to handle a string & hash
15120 getBaseline: function( origin, original ) {
15122 switch ( origin[ 0 ] ) {
15123 case "top": y = 0; break;
15124 case "middle": y = 0.5; break;
15125 case "bottom": y = 1; break;
15126 default: y = origin[ 0 ] / original.height;
15128 switch ( origin[ 1 ] ) {
15129 case "left": x = 0; break;
15130 case "center": x = 0.5; break;
15131 case "right": x = 1; break;
15132 default: x = origin[ 1 ] / original.width;
15140 // Wraps the element around a wrapper that copies position properties
15141 createWrapper: function( element ) {
15143 // if the element is already wrapped, return it
15144 if ( element.parent().is( ".ui-effects-wrapper" )) {
15145 return element.parent();
15148 // wrap the element
15150 width: element.outerWidth(true),
15151 height: element.outerHeight(true),
15152 "float": element.css( "float" )
15154 wrapper = $( "<div></div>" )
15155 .addClass( "ui-effects-wrapper" )
15158 background: "transparent",
15163 // Store the size in case width/height are defined in % - Fixes #5245
15165 width: element.width(),
15166 height: element.height()
15168 active = document.activeElement;
15170 // support: Firefox
15171 // Firefox incorrectly exposes anonymous content
15172 // https://bugzilla.mozilla.org/show_bug.cgi?id=561664
15176 active = document.body;
15179 element.wrap( wrapper );
15181 // Fixes #7595 - Elements lose focus when wrapped.
15182 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
15183 $( active ).focus();
15186 wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element
15188 // transfer positioning properties to the wrapper
15189 if ( element.css( "position" ) === "static" ) {
15190 wrapper.css({ position: "relative" });
15191 element.css({ position: "relative" });
15194 position: element.css( "position" ),
15195 zIndex: element.css( "z-index" )
15197 $.each([ "top", "left", "bottom", "right" ], function(i, pos) {
15198 props[ pos ] = element.css( pos );
15199 if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
15200 props[ pos ] = "auto";
15204 position: "relative",
15213 return wrapper.css( props ).show();
15216 removeWrapper: function( element ) {
15217 var active = document.activeElement;
15219 if ( element.parent().is( ".ui-effects-wrapper" ) ) {
15220 element.parent().replaceWith( element );
15222 // Fixes #7595 - Elements lose focus when wrapped.
15223 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
15224 $( active ).focus();
15231 setTransition: function( element, list, factor, value ) {
15232 value = value || {};
15233 $.each( list, function( i, x ) {
15234 var unit = element.cssUnit( x );
15235 if ( unit[ 0 ] > 0 ) {
15236 value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
15243 // return an effect options object for the given parameters:
15244 function _normalizeArguments( effect, options, speed, callback ) {
15246 // allow passing all options as the first parameter
15247 if ( $.isPlainObject( effect ) ) {
15249 effect = effect.effect;
15252 // convert to an object
15253 effect = { effect: effect };
15255 // catch (effect, null, ...)
15256 if ( options == null ) {
15260 // catch (effect, callback)
15261 if ( $.isFunction( options ) ) {
15262 callback = options;
15267 // catch (effect, speed, ?)
15268 if ( typeof options === "number" || $.fx.speeds[ options ] ) {
15274 // catch (effect, options, callback)
15275 if ( $.isFunction( speed ) ) {
15280 // add options to effect
15282 $.extend( effect, options );
15285 speed = speed || options.duration;
15286 effect.duration = $.fx.off ? 0 :
15287 typeof speed === "number" ? speed :
15288 speed in $.fx.speeds ? $.fx.speeds[ speed ] :
15289 $.fx.speeds._default;
15291 effect.complete = callback || options.complete;
15296 function standardAnimationOption( option ) {
15297 // Valid standard speeds (nothing, number, named speed)
15298 if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) {
15302 // Invalid strings - treat as "normal" speed
15303 if ( typeof option === "string" && !$.effects.effect[ option ] ) {
15307 // Complete callback
15308 if ( $.isFunction( option ) ) {
15312 // Options hash (but not naming an effect)
15313 if ( typeof option === "object" && !option.effect ) {
15317 // Didn't match any standard API
15322 effect: function( /* effect, options, speed, callback */ ) {
15323 var args = _normalizeArguments.apply( this, arguments ),
15325 queue = args.queue,
15326 effectMethod = $.effects.effect[ args.effect ];
15328 if ( $.fx.off || !effectMethod ) {
15329 // delegate to the original method (e.g., .show()) if possible
15331 return this[ mode ]( args.duration, args.complete );
15333 return this.each( function() {
15334 if ( args.complete ) {
15335 args.complete.call( this );
15341 function run( next ) {
15342 var elem = $( this ),
15343 complete = args.complete,
15347 if ( $.isFunction( complete ) ) {
15348 complete.call( elem[0] );
15350 if ( $.isFunction( next ) ) {
15355 // If the element already has the correct final state, delegate to
15356 // the core methods so the internal tracking of "olddisplay" works.
15357 if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
15361 effectMethod.call( elem[0], args, done );
15365 return queue === false ? this.each( run ) : this.queue( queue || "fx", run );
15368 show: (function( orig ) {
15369 return function( option ) {
15370 if ( standardAnimationOption( option ) ) {
15371 return orig.apply( this, arguments );
15373 var args = _normalizeArguments.apply( this, arguments );
15374 args.mode = "show";
15375 return this.effect.call( this, args );
15380 hide: (function( orig ) {
15381 return function( option ) {
15382 if ( standardAnimationOption( option ) ) {
15383 return orig.apply( this, arguments );
15385 var args = _normalizeArguments.apply( this, arguments );
15386 args.mode = "hide";
15387 return this.effect.call( this, args );
15392 toggle: (function( orig ) {
15393 return function( option ) {
15394 if ( standardAnimationOption( option ) || typeof option === "boolean" ) {
15395 return orig.apply( this, arguments );
15397 var args = _normalizeArguments.apply( this, arguments );
15398 args.mode = "toggle";
15399 return this.effect.call( this, args );
15404 // helper functions
15405 cssUnit: function(key) {
15406 var style = this.css( key ),
15409 $.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
15410 if ( style.indexOf( unit ) > 0 ) {
15411 val = [ parseFloat( style ), unit ];
15420 /******************************************************************************/
15421 /*********************************** EASING ***********************************/
15422 /******************************************************************************/
15426 // based on easing equations from Robert Penner (http://www.robertpenner.com/easing)
15428 var baseEasings = {};
15430 $.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
15431 baseEasings[ name ] = function( p ) {
15432 return Math.pow( p, i + 2 );
15436 $.extend( baseEasings, {
15437 Sine: function( p ) {
15438 return 1 - Math.cos( p * Math.PI / 2 );
15440 Circ: function( p ) {
15441 return 1 - Math.sqrt( 1 - p * p );
15443 Elastic: function( p ) {
15444 return p === 0 || p === 1 ? p :
15445 -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 );
15447 Back: function( p ) {
15448 return p * p * ( 3 * p - 2 );
15450 Bounce: function( p ) {
15454 while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
15455 return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
15459 $.each( baseEasings, function( name, easeIn ) {
15460 $.easing[ "easeIn" + name ] = easeIn;
15461 $.easing[ "easeOut" + name ] = function( p ) {
15462 return 1 - easeIn( 1 - p );
15464 $.easing[ "easeInOut" + name ] = function( p ) {
15466 easeIn( p * 2 ) / 2 :
15467 1 - easeIn( p * -2 + 2 ) / 2;
15473 var effect = $.effects;
15477 * jQuery UI Effects Blind 1.11.3
15478 * http://jqueryui.com
15480 * Copyright jQuery Foundation and other contributors
15481 * Released under the MIT license.
15482 * http://jquery.org/license
15484 * http://api.jqueryui.com/blind-effect/
15488 var effectBlind = $.effects.effect.blind = function( o, done ) {
15490 var el = $( this ),
15491 rvertical = /up|down|vertical/,
15492 rpositivemotion = /up|left|vertical|horizontal/,
15493 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
15494 mode = $.effects.setMode( el, o.mode || "hide" ),
15495 direction = o.direction || "up",
15496 vertical = rvertical.test( direction ),
15497 ref = vertical ? "height" : "width",
15498 ref2 = vertical ? "top" : "left",
15499 motion = rpositivemotion.test( direction ),
15501 show = mode === "show",
15502 wrapper, distance, margin;
15504 // if already wrapped, the wrapper's properties are my property. #6245
15505 if ( el.parent().is( ".ui-effects-wrapper" ) ) {
15506 $.effects.save( el.parent(), props );
15508 $.effects.save( el, props );
15511 wrapper = $.effects.createWrapper( el ).css({
15515 distance = wrapper[ ref ]();
15516 margin = parseFloat( wrapper.css( ref2 ) ) || 0;
15518 animation[ ref ] = show ? distance : 0;
15521 .css( vertical ? "bottom" : "right", 0 )
15522 .css( vertical ? "top" : "left", "auto" )
15523 .css({ position: "absolute" });
15525 animation[ ref2 ] = show ? margin : distance + margin;
15528 // start at 0 if we are showing
15530 wrapper.css( ref, 0 );
15532 wrapper.css( ref2, margin + distance );
15537 wrapper.animate( animation, {
15538 duration: o.duration,
15541 complete: function() {
15542 if ( mode === "hide" ) {
15545 $.effects.restore( el, props );
15546 $.effects.removeWrapper( el );
15554 * jQuery UI Effects Bounce 1.11.3
15555 * http://jqueryui.com
15557 * Copyright jQuery Foundation and other contributors
15558 * Released under the MIT license.
15559 * http://jquery.org/license
15561 * http://api.jqueryui.com/bounce-effect/
15565 var effectBounce = $.effects.effect.bounce = function( o, done ) {
15566 var el = $( this ),
15567 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
15570 mode = $.effects.setMode( el, o.mode || "effect" ),
15571 hide = mode === "hide",
15572 show = mode === "show",
15573 direction = o.direction || "up",
15574 distance = o.distance,
15575 times = o.times || 5,
15577 // number of internal animations
15578 anims = times * 2 + ( show || hide ? 1 : 0 ),
15579 speed = o.duration / anims,
15583 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
15584 motion = ( direction === "up" || direction === "left" ),
15589 // we will need to re-assemble the queue to stack our animations in place
15590 queue = el.queue(),
15591 queuelen = queue.length;
15593 // Avoid touching opacity to prevent clearType and PNG issues in IE
15594 if ( show || hide ) {
15595 props.push( "opacity" );
15598 $.effects.save( el, props );
15600 $.effects.createWrapper( el ); // Create Wrapper
15602 // default distance for the BIGGEST bounce is the outer Distance / 3
15604 distance = el[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
15608 downAnim = { opacity: 1 };
15609 downAnim[ ref ] = 0;
15611 // if we are showing, force opacity 0 and set the initial position
15612 // then do the "first" animation
15613 el.css( "opacity", 0 )
15614 .css( ref, motion ? -distance * 2 : distance * 2 )
15615 .animate( downAnim, speed, easing );
15618 // start at the smallest distance if we are hiding
15620 distance = distance / Math.pow( 2, times - 1 );
15624 downAnim[ ref ] = 0;
15625 // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
15626 for ( i = 0; i < times; i++ ) {
15628 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
15630 el.animate( upAnim, speed, easing )
15631 .animate( downAnim, speed, easing );
15633 distance = hide ? distance * 2 : distance / 2;
15636 // Last Bounce when Hiding
15638 upAnim = { opacity: 0 };
15639 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
15641 el.animate( upAnim, speed, easing );
15644 el.queue(function() {
15648 $.effects.restore( el, props );
15649 $.effects.removeWrapper( el );
15653 // inject all the animations we just queued to be first in line (after "inprogress")
15654 if ( queuelen > 1) {
15655 queue.splice.apply( queue,
15656 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
15664 * jQuery UI Effects Clip 1.11.3
15665 * http://jqueryui.com
15667 * Copyright jQuery Foundation and other contributors
15668 * Released under the MIT license.
15669 * http://jquery.org/license
15671 * http://api.jqueryui.com/clip-effect/
15675 var effectClip = $.effects.effect.clip = function( o, done ) {
15677 var el = $( this ),
15678 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
15679 mode = $.effects.setMode( el, o.mode || "hide" ),
15680 show = mode === "show",
15681 direction = o.direction || "vertical",
15682 vert = direction === "vertical",
15683 size = vert ? "height" : "width",
15684 position = vert ? "top" : "left",
15686 wrapper, animate, distance;
15689 $.effects.save( el, props );
15693 wrapper = $.effects.createWrapper( el ).css({
15696 animate = ( el[0].tagName === "IMG" ) ? wrapper : el;
15697 distance = animate[ size ]();
15701 animate.css( size, 0 );
15702 animate.css( position, distance / 2 );
15705 // Create Animation Object:
15706 animation[ size ] = show ? distance : 0;
15707 animation[ position ] = show ? 0 : distance / 2;
15710 animate.animate( animation, {
15712 duration: o.duration,
15714 complete: function() {
15718 $.effects.restore( el, props );
15719 $.effects.removeWrapper( el );
15728 * jQuery UI Effects Drop 1.11.3
15729 * http://jqueryui.com
15731 * Copyright jQuery Foundation and other contributors
15732 * Released under the MIT license.
15733 * http://jquery.org/license
15735 * http://api.jqueryui.com/drop-effect/
15739 var effectDrop = $.effects.effect.drop = function( o, done ) {
15741 var el = $( this ),
15742 props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ],
15743 mode = $.effects.setMode( el, o.mode || "hide" ),
15744 show = mode === "show",
15745 direction = o.direction || "left",
15746 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
15747 motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg",
15749 opacity: show ? 1 : 0
15754 $.effects.save( el, props );
15756 $.effects.createWrapper( el );
15758 distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ) / 2;
15762 .css( "opacity", 0 )
15763 .css( ref, motion === "pos" ? -distance : distance );
15767 animation[ ref ] = ( show ?
15768 ( motion === "pos" ? "+=" : "-=" ) :
15769 ( motion === "pos" ? "-=" : "+=" ) ) +
15773 el.animate( animation, {
15775 duration: o.duration,
15777 complete: function() {
15778 if ( mode === "hide" ) {
15781 $.effects.restore( el, props );
15782 $.effects.removeWrapper( el );
15790 * jQuery UI Effects Explode 1.11.3
15791 * http://jqueryui.com
15793 * Copyright jQuery Foundation and other contributors
15794 * Released under the MIT license.
15795 * http://jquery.org/license
15797 * http://api.jqueryui.com/explode-effect/
15801 var effectExplode = $.effects.effect.explode = function( o, done ) {
15803 var rows = o.pieces ? Math.round( Math.sqrt( o.pieces ) ) : 3,
15806 mode = $.effects.setMode( el, o.mode || "hide" ),
15807 show = mode === "show",
15809 // show and then visibility:hidden the element before calculating offset
15810 offset = el.show().css( "visibility", "hidden" ).offset(),
15812 // width and height of a piece
15813 width = Math.ceil( el.outerWidth() / cells ),
15814 height = Math.ceil( el.outerHeight() / rows ),
15818 i, j, left, top, mx, my;
15820 // children animate complete:
15821 function childComplete() {
15822 pieces.push( this );
15823 if ( pieces.length === rows * cells ) {
15828 // clone the element for each row and cell.
15829 for ( i = 0; i < rows ; i++ ) { // ===>
15830 top = offset.top + i * height;
15831 my = i - ( rows - 1 ) / 2 ;
15833 for ( j = 0; j < cells ; j++ ) { // |||
15834 left = offset.left + j * width;
15835 mx = j - ( cells - 1 ) / 2 ;
15837 // Create a clone of the now hidden main element that will be absolute positioned
15838 // within a wrapper div off the -left and -top equal to size of our pieces
15841 .appendTo( "body" )
15842 .wrap( "<div></div>" )
15844 position: "absolute",
15845 visibility: "visible",
15850 // select the wrapper - make it overflow: hidden and absolute positioned based on
15851 // where the original was located +left and +top equal to the size of pieces
15853 .addClass( "ui-effects-explode" )
15855 position: "absolute",
15856 overflow: "hidden",
15859 left: left + ( show ? mx * width : 0 ),
15860 top: top + ( show ? my * height : 0 ),
15861 opacity: show ? 0 : 1
15863 left: left + ( show ? 0 : mx * width ),
15864 top: top + ( show ? 0 : my * height ),
15865 opacity: show ? 1 : 0
15866 }, o.duration || 500, o.easing, childComplete );
15870 function animComplete() {
15872 visibility: "visible"
15874 $( pieces ).remove();
15884 * jQuery UI Effects Fade 1.11.3
15885 * http://jqueryui.com
15887 * Copyright jQuery Foundation and other contributors
15888 * Released under the MIT license.
15889 * http://jquery.org/license
15891 * http://api.jqueryui.com/fade-effect/
15895 var effectFade = $.effects.effect.fade = function( o, done ) {
15896 var el = $( this ),
15897 mode = $.effects.setMode( el, o.mode || "toggle" );
15903 duration: o.duration,
15911 * jQuery UI Effects Fold 1.11.3
15912 * http://jqueryui.com
15914 * Copyright jQuery Foundation and other contributors
15915 * Released under the MIT license.
15916 * http://jquery.org/license
15918 * http://api.jqueryui.com/fold-effect/
15922 var effectFold = $.effects.effect.fold = function( o, done ) {
15925 var el = $( this ),
15926 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
15927 mode = $.effects.setMode( el, o.mode || "hide" ),
15928 show = mode === "show",
15929 hide = mode === "hide",
15930 size = o.size || 15,
15931 percent = /([0-9]+)%/.exec( size ),
15932 horizFirst = !!o.horizFirst,
15933 widthFirst = show !== horizFirst,
15934 ref = widthFirst ? [ "width", "height" ] : [ "height", "width" ],
15935 duration = o.duration / 2,
15940 $.effects.save( el, props );
15944 wrapper = $.effects.createWrapper( el ).css({
15947 distance = widthFirst ?
15948 [ wrapper.width(), wrapper.height() ] :
15949 [ wrapper.height(), wrapper.width() ];
15952 size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
15955 wrapper.css( horizFirst ? {
15965 animation1[ ref[ 0 ] ] = show ? distance[ 0 ] : size;
15966 animation2[ ref[ 1 ] ] = show ? distance[ 1 ] : 0;
15970 .animate( animation1, duration, o.easing )
15971 .animate( animation2, duration, o.easing, function() {
15975 $.effects.restore( el, props );
15976 $.effects.removeWrapper( el );
15984 * jQuery UI Effects Highlight 1.11.3
15985 * http://jqueryui.com
15987 * Copyright jQuery Foundation and other contributors
15988 * Released under the MIT license.
15989 * http://jquery.org/license
15991 * http://api.jqueryui.com/highlight-effect/
15995 var effectHighlight = $.effects.effect.highlight = function( o, done ) {
15996 var elem = $( this ),
15997 props = [ "backgroundImage", "backgroundColor", "opacity" ],
15998 mode = $.effects.setMode( elem, o.mode || "show" ),
16000 backgroundColor: elem.css( "backgroundColor" )
16003 if (mode === "hide") {
16004 animation.opacity = 0;
16007 $.effects.save( elem, props );
16012 backgroundImage: "none",
16013 backgroundColor: o.color || "#ffff99"
16015 .animate( animation, {
16017 duration: o.duration,
16019 complete: function() {
16020 if ( mode === "hide" ) {
16023 $.effects.restore( elem, props );
16031 * jQuery UI Effects Size 1.11.3
16032 * http://jqueryui.com
16034 * Copyright jQuery Foundation and other contributors
16035 * Released under the MIT license.
16036 * http://jquery.org/license
16038 * http://api.jqueryui.com/size-effect/
16042 var effectSize = $.effects.effect.size = function( o, done ) {
16045 var original, baseline, factor,
16047 props0 = [ "position", "top", "bottom", "left", "right", "width", "height", "overflow", "opacity" ],
16050 props1 = [ "position", "top", "bottom", "left", "right", "overflow", "opacity" ],
16052 // Copy for children
16053 props2 = [ "width", "height", "overflow" ],
16054 cProps = [ "fontSize" ],
16055 vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
16056 hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],
16059 mode = $.effects.setMode( el, o.mode || "effect" ),
16060 restore = o.restore || mode !== "effect",
16061 scale = o.scale || "both",
16062 origin = o.origin || [ "middle", "center" ],
16063 position = el.css( "position" ),
16064 props = restore ? props0 : props1,
16072 if ( mode === "show" ) {
16076 height: el.height(),
16078 outerHeight: el.outerHeight(),
16079 outerWidth: el.outerWidth()
16082 if ( o.mode === "toggle" && mode === "show" ) {
16083 el.from = o.to || zero;
16084 el.to = o.from || original;
16086 el.from = o.from || ( mode === "show" ? zero : original );
16087 el.to = o.to || ( mode === "hide" ? zero : original );
16090 // Set scaling factor
16093 y: el.from.height / original.height,
16094 x: el.from.width / original.width
16097 y: el.to.height / original.height,
16098 x: el.to.width / original.width
16102 // Scale the css box
16103 if ( scale === "box" || scale === "both" ) {
16105 // Vertical props scaling
16106 if ( factor.from.y !== factor.to.y ) {
16107 props = props.concat( vProps );
16108 el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from );
16109 el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to );
16112 // Horizontal props scaling
16113 if ( factor.from.x !== factor.to.x ) {
16114 props = props.concat( hProps );
16115 el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from );
16116 el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to );
16120 // Scale the content
16121 if ( scale === "content" || scale === "both" ) {
16123 // Vertical props scaling
16124 if ( factor.from.y !== factor.to.y ) {
16125 props = props.concat( cProps ).concat( props2 );
16126 el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from );
16127 el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to );
16131 $.effects.save( el, props );
16133 $.effects.createWrapper( el );
16134 el.css( "overflow", "hidden" ).css( el.from );
16137 if (origin) { // Calculate baseline shifts
16138 baseline = $.effects.getBaseline( origin, original );
16139 el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y;
16140 el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x;
16141 el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y;
16142 el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x;
16144 el.css( el.from ); // set top & left
16147 if ( scale === "content" || scale === "both" ) { // Scale the children
16149 // Add margins/font-size
16150 vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat(cProps);
16151 hProps = hProps.concat([ "marginLeft", "marginRight" ]);
16152 props2 = props0.concat(vProps).concat(hProps);
16154 el.find( "*[width]" ).each( function() {
16155 var child = $( this ),
16157 height: child.height(),
16158 width: child.width(),
16159 outerHeight: child.outerHeight(),
16160 outerWidth: child.outerWidth()
16163 $.effects.save(child, props2);
16167 height: c_original.height * factor.from.y,
16168 width: c_original.width * factor.from.x,
16169 outerHeight: c_original.outerHeight * factor.from.y,
16170 outerWidth: c_original.outerWidth * factor.from.x
16173 height: c_original.height * factor.to.y,
16174 width: c_original.width * factor.to.x,
16175 outerHeight: c_original.height * factor.to.y,
16176 outerWidth: c_original.width * factor.to.x
16179 // Vertical props scaling
16180 if ( factor.from.y !== factor.to.y ) {
16181 child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from );
16182 child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to );
16185 // Horizontal props scaling
16186 if ( factor.from.x !== factor.to.x ) {
16187 child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from );
16188 child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to );
16191 // Animate children
16192 child.css( child.from );
16193 child.animate( child.to, o.duration, o.easing, function() {
16195 // Restore children
16197 $.effects.restore( child, props2 );
16204 el.animate( el.to, {
16206 duration: o.duration,
16208 complete: function() {
16209 if ( el.to.opacity === 0 ) {
16210 el.css( "opacity", el.from.opacity );
16212 if ( mode === "hide" ) {
16215 $.effects.restore( el, props );
16218 // we need to calculate our new positioning based on the scaling
16219 if ( position === "static" ) {
16221 position: "relative",
16226 $.each([ "top", "left" ], function( idx, pos ) {
16227 el.css( pos, function( _, str ) {
16228 var val = parseInt( str, 10 ),
16229 toRef = idx ? el.to.left : el.to.top;
16231 // if original was "auto", recalculate the new value from wrapper
16232 if ( str === "auto" ) {
16233 return toRef + "px";
16236 return val + toRef + "px";
16242 $.effects.removeWrapper( el );
16251 * jQuery UI Effects Scale 1.11.3
16252 * http://jqueryui.com
16254 * Copyright jQuery Foundation and other contributors
16255 * Released under the MIT license.
16256 * http://jquery.org/license
16258 * http://api.jqueryui.com/scale-effect/
16262 var effectScale = $.effects.effect.scale = function( o, done ) {
16265 var el = $( this ),
16266 options = $.extend( true, {}, o ),
16267 mode = $.effects.setMode( el, o.mode || "effect" ),
16268 percent = parseInt( o.percent, 10 ) ||
16269 ( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === "hide" ? 0 : 100 ) ),
16270 direction = o.direction || "both",
16273 height: el.height(),
16275 outerHeight: el.outerHeight(),
16276 outerWidth: el.outerWidth()
16279 y: direction !== "horizontal" ? (percent / 100) : 1,
16280 x: direction !== "vertical" ? (percent / 100) : 1
16283 // We are going to pass this effect to the size effect:
16284 options.effect = "size";
16285 options.queue = false;
16286 options.complete = done;
16288 // Set default origin and restore for show/hide
16289 if ( mode !== "effect" ) {
16290 options.origin = origin || [ "middle", "center" ];
16291 options.restore = true;
16294 options.from = o.from || ( mode === "show" ? {
16301 height: original.height * factor.y,
16302 width: original.width * factor.x,
16303 outerHeight: original.outerHeight * factor.y,
16304 outerWidth: original.outerWidth * factor.x
16307 // Fade option to support puff
16308 if ( options.fade ) {
16309 if ( mode === "show" ) {
16310 options.from.opacity = 0;
16311 options.to.opacity = 1;
16313 if ( mode === "hide" ) {
16314 options.from.opacity = 1;
16315 options.to.opacity = 0;
16320 el.effect( options );
16326 * jQuery UI Effects Puff 1.11.3
16327 * http://jqueryui.com
16329 * Copyright jQuery Foundation and other contributors
16330 * Released under the MIT license.
16331 * http://jquery.org/license
16333 * http://api.jqueryui.com/puff-effect/
16337 var effectPuff = $.effects.effect.puff = function( o, done ) {
16338 var elem = $( this ),
16339 mode = $.effects.setMode( elem, o.mode || "hide" ),
16340 hide = mode === "hide",
16341 percent = parseInt( o.percent, 10 ) || 150,
16342 factor = percent / 100,
16344 height: elem.height(),
16345 width: elem.width(),
16346 outerHeight: elem.outerHeight(),
16347 outerWidth: elem.outerWidth()
16356 percent: hide ? percent : 100,
16360 height: original.height * factor,
16361 width: original.width * factor,
16362 outerHeight: original.outerHeight * factor,
16363 outerWidth: original.outerWidth * factor
16372 * jQuery UI Effects Pulsate 1.11.3
16373 * http://jqueryui.com
16375 * Copyright jQuery Foundation and other contributors
16376 * Released under the MIT license.
16377 * http://jquery.org/license
16379 * http://api.jqueryui.com/pulsate-effect/
16383 var effectPulsate = $.effects.effect.pulsate = function( o, done ) {
16384 var elem = $( this ),
16385 mode = $.effects.setMode( elem, o.mode || "show" ),
16386 show = mode === "show",
16387 hide = mode === "hide",
16388 showhide = ( show || mode === "hide" ),
16390 // showing or hiding leaves of the "last" animation
16391 anims = ( ( o.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
16392 duration = o.duration / anims,
16394 queue = elem.queue(),
16395 queuelen = queue.length,
16398 if ( show || !elem.is(":visible")) {
16399 elem.css( "opacity", 0 ).show();
16403 // anims - 1 opacity "toggles"
16404 for ( i = 1; i < anims; i++ ) {
16407 }, duration, o.easing );
16408 animateTo = 1 - animateTo;
16413 }, duration, o.easing);
16415 elem.queue(function() {
16422 // We just queued up "anims" animations, we need to put them next in the queue
16423 if ( queuelen > 1 ) {
16424 queue.splice.apply( queue,
16425 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
16432 * jQuery UI Effects Shake 1.11.3
16433 * http://jqueryui.com
16435 * Copyright jQuery Foundation and other contributors
16436 * Released under the MIT license.
16437 * http://jquery.org/license
16439 * http://api.jqueryui.com/shake-effect/
16443 var effectShake = $.effects.effect.shake = function( o, done ) {
16445 var el = $( this ),
16446 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
16447 mode = $.effects.setMode( el, o.mode || "effect" ),
16448 direction = o.direction || "left",
16449 distance = o.distance || 20,
16450 times = o.times || 3,
16451 anims = times * 2 + 1,
16452 speed = Math.round( o.duration / anims ),
16453 ref = (direction === "up" || direction === "down") ? "top" : "left",
16454 positiveMotion = (direction === "up" || direction === "left"),
16460 // we will need to re-assemble the queue to stack our animations in place
16461 queue = el.queue(),
16462 queuelen = queue.length;
16464 $.effects.save( el, props );
16466 $.effects.createWrapper( el );
16469 animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
16470 animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
16471 animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;
16474 el.animate( animation, speed, o.easing );
16477 for ( i = 1; i < times; i++ ) {
16478 el.animate( animation1, speed, o.easing ).animate( animation2, speed, o.easing );
16481 .animate( animation1, speed, o.easing )
16482 .animate( animation, speed / 2, o.easing )
16483 .queue(function() {
16484 if ( mode === "hide" ) {
16487 $.effects.restore( el, props );
16488 $.effects.removeWrapper( el );
16492 // inject all the animations we just queued to be first in line (after "inprogress")
16493 if ( queuelen > 1) {
16494 queue.splice.apply( queue,
16495 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
16503 * jQuery UI Effects Slide 1.11.3
16504 * http://jqueryui.com
16506 * Copyright jQuery Foundation and other contributors
16507 * Released under the MIT license.
16508 * http://jquery.org/license
16510 * http://api.jqueryui.com/slide-effect/
16514 var effectSlide = $.effects.effect.slide = function( o, done ) {
16517 var el = $( this ),
16518 props = [ "position", "top", "bottom", "left", "right", "width", "height" ],
16519 mode = $.effects.setMode( el, o.mode || "show" ),
16520 show = mode === "show",
16521 direction = o.direction || "left",
16522 ref = (direction === "up" || direction === "down") ? "top" : "left",
16523 positiveMotion = (direction === "up" || direction === "left"),
16528 $.effects.save( el, props );
16530 distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true );
16532 $.effects.createWrapper( el ).css({
16537 el.css( ref, positiveMotion ? (isNaN(distance) ? "-" + distance : -distance) : distance );
16541 animation[ ref ] = ( show ?
16542 ( positiveMotion ? "+=" : "-=") :
16543 ( positiveMotion ? "-=" : "+=")) +
16547 el.animate( animation, {
16549 duration: o.duration,
16551 complete: function() {
16552 if ( mode === "hide" ) {
16555 $.effects.restore( el, props );
16556 $.effects.removeWrapper( el );
16564 * jQuery UI Effects Transfer 1.11.3
16565 * http://jqueryui.com
16567 * Copyright jQuery Foundation and other contributors
16568 * Released under the MIT license.
16569 * http://jquery.org/license
16571 * http://api.jqueryui.com/transfer-effect/
16575 var effectTransfer = $.effects.effect.transfer = function( o, done ) {
16576 var elem = $( this ),
16577 target = $( o.to ),
16578 targetFixed = target.css( "position" ) === "fixed",
16580 fixTop = targetFixed ? body.scrollTop() : 0,
16581 fixLeft = targetFixed ? body.scrollLeft() : 0,
16582 endPosition = target.offset(),
16584 top: endPosition.top - fixTop,
16585 left: endPosition.left - fixLeft,
16586 height: target.innerHeight(),
16587 width: target.innerWidth()
16589 startPosition = elem.offset(),
16590 transfer = $( "<div class='ui-effects-transfer'></div>" )
16591 .appendTo( document.body )
16592 .addClass( o.className )
16594 top: startPosition.top - fixTop,
16595 left: startPosition.left - fixLeft,
16596 height: elem.innerHeight(),
16597 width: elem.innerWidth(),
16598 position: targetFixed ? "fixed" : "absolute"
16600 .animate( animation, o.duration, o.easing, function() {