1 /*! jQuery UI - v1.11.3 - 2015-02-12
3 * Includes: core.js, widget.js, mouse.js, position.js, accordion.js, autocomplete.js, button.js, datepicker.js, dialog.js, draggable.js, droppable.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, menu.js, progressbar.js, resizable.js, selectable.js, selectmenu.js, slider.js, sortable.js, spinner.js, tabs.js, tooltip.js
4 * Copyright jQuery Foundation and other contributors; Licensed MIT */
7 if ( typeof define === "function" && define.amd ) {
9 // AMD. Register as an anonymous module.
10 define([ "jquery" ], factory );
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 Accordion 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/accordion/
1564 var accordion = $.widget( "ui.accordion", {
1571 header: "> li > :first-child,> :not(li):even",
1572 heightStyle: "auto",
1574 activeHeader: "ui-icon-triangle-1-s",
1575 header: "ui-icon-triangle-1-e"
1580 beforeActivate: null
1584 borderTopWidth: "hide",
1585 borderBottomWidth: "hide",
1587 paddingBottom: "hide",
1592 borderTopWidth: "show",
1593 borderBottomWidth: "show",
1595 paddingBottom: "show",
1599 _create: function() {
1600 var options = this.options;
1601 this.prevShow = this.prevHide = $();
1602 this.element.addClass( "ui-accordion ui-widget ui-helper-reset" )
1604 .attr( "role", "tablist" );
1606 // don't allow collapsible: false and active: false / null
1607 if ( !options.collapsible && (options.active === false || options.active == null) ) {
1611 this._processPanels();
1612 // handle negative values
1613 if ( options.active < 0 ) {
1614 options.active += this.headers.length;
1619 _getCreateEventData: function() {
1621 header: this.active,
1622 panel: !this.active.length ? $() : this.active.next()
1626 _createIcons: function() {
1627 var icons = this.options.icons;
1630 .addClass( "ui-accordion-header-icon ui-icon " + icons.header )
1631 .prependTo( this.headers );
1632 this.active.children( ".ui-accordion-header-icon" )
1633 .removeClass( icons.header )
1634 .addClass( icons.activeHeader );
1635 this.headers.addClass( "ui-accordion-icons" );
1639 _destroyIcons: function() {
1641 .removeClass( "ui-accordion-icons" )
1642 .children( ".ui-accordion-header-icon" )
1646 _destroy: function() {
1649 // clean up main element
1651 .removeClass( "ui-accordion ui-widget ui-helper-reset" )
1652 .removeAttr( "role" );
1656 .removeClass( "ui-accordion-header ui-accordion-header-active ui-state-default " +
1657 "ui-corner-all ui-state-active ui-state-disabled ui-corner-top" )
1658 .removeAttr( "role" )
1659 .removeAttr( "aria-expanded" )
1660 .removeAttr( "aria-selected" )
1661 .removeAttr( "aria-controls" )
1662 .removeAttr( "tabIndex" )
1665 this._destroyIcons();
1667 // clean up content panels
1668 contents = this.headers.next()
1669 .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom " +
1670 "ui-accordion-content ui-accordion-content-active ui-state-disabled" )
1671 .css( "display", "" )
1672 .removeAttr( "role" )
1673 .removeAttr( "aria-hidden" )
1674 .removeAttr( "aria-labelledby" )
1677 if ( this.options.heightStyle !== "content" ) {
1678 contents.css( "height", "" );
1682 _setOption: function( key, value ) {
1683 if ( key === "active" ) {
1684 // _activate() will handle invalid values and update this.options
1685 this._activate( value );
1689 if ( key === "event" ) {
1690 if ( this.options.event ) {
1691 this._off( this.headers, this.options.event );
1693 this._setupEvents( value );
1696 this._super( key, value );
1698 // setting collapsible: false while collapsed; open first panel
1699 if ( key === "collapsible" && !value && this.options.active === false ) {
1700 this._activate( 0 );
1703 if ( key === "icons" ) {
1704 this._destroyIcons();
1706 this._createIcons();
1710 // #5332 - opacity doesn't cascade to positioned elements in IE
1711 // so we need to add the disabled class to the headers and panels
1712 if ( key === "disabled" ) {
1714 .toggleClass( "ui-state-disabled", !!value )
1715 .attr( "aria-disabled", value );
1716 this.headers.add( this.headers.next() )
1717 .toggleClass( "ui-state-disabled", !!value );
1721 _keydown: function( event ) {
1722 if ( event.altKey || event.ctrlKey ) {
1726 var keyCode = $.ui.keyCode,
1727 length = this.headers.length,
1728 currentIndex = this.headers.index( event.target ),
1731 switch ( event.keyCode ) {
1734 toFocus = this.headers[ ( currentIndex + 1 ) % length ];
1738 toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
1742 this._eventHandler( event );
1745 toFocus = this.headers[ 0 ];
1748 toFocus = this.headers[ length - 1 ];
1753 $( event.target ).attr( "tabIndex", -1 );
1754 $( toFocus ).attr( "tabIndex", 0 );
1756 event.preventDefault();
1760 _panelKeyDown: function( event ) {
1761 if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
1762 $( event.currentTarget ).prev().focus();
1766 refresh: function() {
1767 var options = this.options;
1768 this._processPanels();
1770 // was collapsed or no panel
1771 if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) {
1772 options.active = false;
1774 // active false only when collapsible is true
1775 } else if ( options.active === false ) {
1776 this._activate( 0 );
1777 // was active, but active panel is gone
1778 } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
1779 // all remaining panel are disabled
1780 if ( this.headers.length === this.headers.find(".ui-state-disabled").length ) {
1781 options.active = false;
1783 // activate previous panel
1785 this._activate( Math.max( 0, options.active - 1 ) );
1787 // was active, active panel still exists
1789 // make sure active index is correct
1790 options.active = this.headers.index( this.active );
1793 this._destroyIcons();
1798 _processPanels: function() {
1799 var prevHeaders = this.headers,
1800 prevPanels = this.panels;
1802 this.headers = this.element.find( this.options.header )
1803 .addClass( "ui-accordion-header ui-state-default ui-corner-all" );
1805 this.panels = this.headers.next()
1806 .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" )
1807 .filter( ":not(.ui-accordion-content-active)" )
1810 // Avoid memory leaks (#10056)
1812 this._off( prevHeaders.not( this.headers ) );
1813 this._off( prevPanels.not( this.panels ) );
1817 _refresh: function() {
1819 options = this.options,
1820 heightStyle = options.heightStyle,
1821 parent = this.element.parent();
1823 this.active = this._findActive( options.active )
1824 .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" )
1825 .removeClass( "ui-corner-all" );
1827 .addClass( "ui-accordion-content-active" )
1831 .attr( "role", "tab" )
1833 var header = $( this ),
1834 headerId = header.uniqueId().attr( "id" ),
1835 panel = header.next(),
1836 panelId = panel.uniqueId().attr( "id" );
1837 header.attr( "aria-controls", panelId );
1838 panel.attr( "aria-labelledby", headerId );
1841 .attr( "role", "tabpanel" );
1846 "aria-selected": "false",
1847 "aria-expanded": "false",
1852 "aria-hidden": "true"
1856 // make sure at least one header is in the tab order
1857 if ( !this.active.length ) {
1858 this.headers.eq( 0 ).attr( "tabIndex", 0 );
1861 "aria-selected": "true",
1862 "aria-expanded": "true",
1867 "aria-hidden": "false"
1871 this._createIcons();
1873 this._setupEvents( options.event );
1875 if ( heightStyle === "fill" ) {
1876 maxHeight = parent.height();
1877 this.element.siblings( ":visible" ).each(function() {
1878 var elem = $( this ),
1879 position = elem.css( "position" );
1881 if ( position === "absolute" || position === "fixed" ) {
1884 maxHeight -= elem.outerHeight( true );
1887 this.headers.each(function() {
1888 maxHeight -= $( this ).outerHeight( true );
1893 $( this ).height( Math.max( 0, maxHeight -
1894 $( this ).innerHeight() + $( this ).height() ) );
1896 .css( "overflow", "auto" );
1897 } else if ( heightStyle === "auto" ) {
1901 maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
1903 .height( maxHeight );
1907 _activate: function( index ) {
1908 var active = this._findActive( index )[ 0 ];
1910 // trying to activate the already active panel
1911 if ( active === this.active[ 0 ] ) {
1915 // trying to collapse, simulate a click on the currently active header
1916 active = active || this.active[ 0 ];
1918 this._eventHandler({
1920 currentTarget: active,
1921 preventDefault: $.noop
1925 _findActive: function( selector ) {
1926 return typeof selector === "number" ? this.headers.eq( selector ) : $();
1929 _setupEvents: function( event ) {
1934 $.each( event.split( " " ), function( index, eventName ) {
1935 events[ eventName ] = "_eventHandler";
1939 this._off( this.headers.add( this.headers.next() ) );
1940 this._on( this.headers, events );
1941 this._on( this.headers.next(), { keydown: "_panelKeyDown" });
1942 this._hoverable( this.headers );
1943 this._focusable( this.headers );
1946 _eventHandler: function( event ) {
1947 var options = this.options,
1948 active = this.active,
1949 clicked = $( event.currentTarget ),
1950 clickedIsActive = clicked[ 0 ] === active[ 0 ],
1951 collapsing = clickedIsActive && options.collapsible,
1952 toShow = collapsing ? $() : clicked.next(),
1953 toHide = active.next(),
1957 newHeader: collapsing ? $() : clicked,
1961 event.preventDefault();
1964 // click on active header, but not collapsible
1965 ( clickedIsActive && !options.collapsible ) ||
1966 // allow canceling activation
1967 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
1971 options.active = collapsing ? false : this.headers.index( clicked );
1973 // when the call to ._toggle() comes after the class changes
1974 // it causes a very odd bug in IE 8 (see #6720)
1975 this.active = clickedIsActive ? $() : clicked;
1976 this._toggle( eventData );
1979 // corner classes on the previously active header stay after the animation
1980 active.removeClass( "ui-accordion-header-active ui-state-active" );
1981 if ( options.icons ) {
1982 active.children( ".ui-accordion-header-icon" )
1983 .removeClass( options.icons.activeHeader )
1984 .addClass( options.icons.header );
1987 if ( !clickedIsActive ) {
1989 .removeClass( "ui-corner-all" )
1990 .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" );
1991 if ( options.icons ) {
1992 clicked.children( ".ui-accordion-header-icon" )
1993 .removeClass( options.icons.header )
1994 .addClass( options.icons.activeHeader );
1999 .addClass( "ui-accordion-content-active" );
2003 _toggle: function( data ) {
2004 var toShow = data.newPanel,
2005 toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
2007 // handle activating a panel during the animation for another activation
2008 this.prevShow.add( this.prevHide ).stop( true, true );
2009 this.prevShow = toShow;
2010 this.prevHide = toHide;
2012 if ( this.options.animate ) {
2013 this._animate( toShow, toHide, data );
2017 this._toggleComplete( data );
2021 "aria-hidden": "true"
2023 toHide.prev().attr({
2024 "aria-selected": "false",
2025 "aria-expanded": "false"
2027 // if we're switching panels, remove the old header from the tab order
2028 // if we're opening from collapsed state, remove the previous header from the tab order
2029 // if we're collapsing, then keep the collapsing header in the tab order
2030 if ( toShow.length && toHide.length ) {
2031 toHide.prev().attr({
2033 "aria-expanded": "false"
2035 } else if ( toShow.length ) {
2036 this.headers.filter(function() {
2037 return parseInt( $( this ).attr( "tabIndex" ), 10 ) === 0;
2039 .attr( "tabIndex", -1 );
2043 .attr( "aria-hidden", "false" )
2046 "aria-selected": "true",
2047 "aria-expanded": "true",
2052 _animate: function( toShow, toHide, data ) {
2053 var total, easing, duration,
2056 down = toShow.length &&
2057 ( !toHide.length || ( toShow.index() < toHide.index() ) ),
2058 animate = this.options.animate || {},
2059 options = down && animate.down || animate,
2060 complete = function() {
2061 that._toggleComplete( data );
2064 if ( typeof options === "number" ) {
2067 if ( typeof options === "string" ) {
2070 // fall back from options to animation in case of partial down settings
2071 easing = easing || options.easing || animate.easing;
2072 duration = duration || options.duration || animate.duration;
2074 if ( !toHide.length ) {
2075 return toShow.animate( this.showProps, duration, easing, complete );
2077 if ( !toShow.length ) {
2078 return toHide.animate( this.hideProps, duration, easing, complete );
2081 total = toShow.show().outerHeight();
2082 toHide.animate( this.hideProps, {
2085 step: function( now, fx ) {
2086 fx.now = Math.round( now );
2091 .animate( this.showProps, {
2095 step: function( now, fx ) {
2096 fx.now = Math.round( now );
2097 if ( fx.prop !== "height" ) {
2099 } else if ( that.options.heightStyle !== "content" ) {
2100 fx.now = Math.round( total - toHide.outerHeight() - adjust );
2107 _toggleComplete: function( data ) {
2108 var toHide = data.oldPanel;
2111 .removeClass( "ui-accordion-content-active" )
2113 .removeClass( "ui-corner-top" )
2114 .addClass( "ui-corner-all" );
2116 // Work around for rendering bug in IE (#5421)
2117 if ( toHide.length ) {
2118 toHide.parent()[ 0 ].className = toHide.parent()[ 0 ].className;
2120 this._trigger( "activate", null, data );
2126 * jQuery UI Menu 1.11.3
2127 * http://jqueryui.com
2129 * Copyright jQuery Foundation and other contributors
2130 * Released under the MIT license.
2131 * http://jquery.org/license
2133 * http://api.jqueryui.com/menu/
2137 var menu = $.widget( "ui.menu", {
2139 defaultElement: "<ul>",
2143 submenu: "ui-icon-carat-1-e"
2159 _create: function() {
2160 this.activeMenu = this.element;
2162 // Flag used to prevent firing of the click handler
2163 // as the event bubbles up through nested menus
2164 this.mouseHandled = false;
2167 .addClass( "ui-menu ui-widget ui-widget-content" )
2168 .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length )
2170 role: this.options.role,
2174 if ( this.options.disabled ) {
2176 .addClass( "ui-state-disabled" )
2177 .attr( "aria-disabled", "true" );
2181 // Prevent focus from sticking to links inside menu after clicking
2182 // them (focus should always stay on UL during navigation).
2183 "mousedown .ui-menu-item": function( event ) {
2184 event.preventDefault();
2186 "click .ui-menu-item": function( event ) {
2187 var target = $( event.target );
2188 if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
2189 this.select( event );
2191 // Only set the mouseHandled flag if the event will bubble, see #9469.
2192 if ( !event.isPropagationStopped() ) {
2193 this.mouseHandled = true;
2196 // Open submenu on click
2197 if ( target.has( ".ui-menu" ).length ) {
2198 this.expand( event );
2199 } else if ( !this.element.is( ":focus" ) && $( this.document[ 0 ].activeElement ).closest( ".ui-menu" ).length ) {
2201 // Redirect focus to the menu
2202 this.element.trigger( "focus", [ true ] );
2204 // If the active item is on the top level, let it stay active.
2205 // Otherwise, blur the active item since it is no longer visible.
2206 if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
2207 clearTimeout( this.timer );
2212 "mouseenter .ui-menu-item": function( event ) {
2213 // Ignore mouse events while typeahead is active, see #10458.
2214 // Prevents focusing the wrong item when typeahead causes a scroll while the mouse
2215 // is over an item in the menu
2216 if ( this.previousFilter ) {
2219 var target = $( event.currentTarget );
2220 // Remove ui-state-active class from siblings of the newly focused menu item
2221 // to avoid a jump caused by adjacent elements both having a class with a border
2222 target.siblings( ".ui-state-active" ).removeClass( "ui-state-active" );
2223 this.focus( event, target );
2225 mouseleave: "collapseAll",
2226 "mouseleave .ui-menu": "collapseAll",
2227 focus: function( event, keepActiveItem ) {
2228 // If there's already an active item, keep it active
2229 // If not, activate the first item
2230 var item = this.active || this.element.find( this.options.items ).eq( 0 );
2232 if ( !keepActiveItem ) {
2233 this.focus( event, item );
2236 blur: function( event ) {
2237 this._delay(function() {
2238 if ( !$.contains( this.element[0], this.document[0].activeElement ) ) {
2239 this.collapseAll( event );
2248 // Clicks outside of a menu collapse any open menus
2249 this._on( this.document, {
2250 click: function( event ) {
2251 if ( this._closeOnDocumentClick( event ) ) {
2252 this.collapseAll( event );
2255 // Reset the mouseHandled flag
2256 this.mouseHandled = false;
2261 _destroy: function() {
2262 // Destroy (sub)menus
2264 .removeAttr( "aria-activedescendant" )
2265 .find( ".ui-menu" ).addBack()
2266 .removeClass( "ui-menu ui-widget ui-widget-content ui-menu-icons ui-front" )
2267 .removeAttr( "role" )
2268 .removeAttr( "tabIndex" )
2269 .removeAttr( "aria-labelledby" )
2270 .removeAttr( "aria-expanded" )
2271 .removeAttr( "aria-hidden" )
2272 .removeAttr( "aria-disabled" )
2276 // Destroy menu items
2277 this.element.find( ".ui-menu-item" )
2278 .removeClass( "ui-menu-item" )
2279 .removeAttr( "role" )
2280 .removeAttr( "aria-disabled" )
2282 .removeClass( "ui-state-hover" )
2283 .removeAttr( "tabIndex" )
2284 .removeAttr( "role" )
2285 .removeAttr( "aria-haspopup" )
2286 .children().each( function() {
2287 var elem = $( this );
2288 if ( elem.data( "ui-menu-submenu-carat" ) ) {
2293 // Destroy menu dividers
2294 this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" );
2297 _keydown: function( event ) {
2298 var match, prev, character, skip,
2299 preventDefault = true;
2301 switch ( event.keyCode ) {
2302 case $.ui.keyCode.PAGE_UP:
2303 this.previousPage( event );
2305 case $.ui.keyCode.PAGE_DOWN:
2306 this.nextPage( event );
2308 case $.ui.keyCode.HOME:
2309 this._move( "first", "first", event );
2311 case $.ui.keyCode.END:
2312 this._move( "last", "last", event );
2314 case $.ui.keyCode.UP:
2315 this.previous( event );
2317 case $.ui.keyCode.DOWN:
2320 case $.ui.keyCode.LEFT:
2321 this.collapse( event );
2323 case $.ui.keyCode.RIGHT:
2324 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
2325 this.expand( event );
2328 case $.ui.keyCode.ENTER:
2329 case $.ui.keyCode.SPACE:
2330 this._activate( event );
2332 case $.ui.keyCode.ESCAPE:
2333 this.collapse( event );
2336 preventDefault = false;
2337 prev = this.previousFilter || "";
2338 character = String.fromCharCode( event.keyCode );
2341 clearTimeout( this.filterTimer );
2343 if ( character === prev ) {
2346 character = prev + character;
2349 match = this._filterMenuItems( character );
2350 match = skip && match.index( this.active.next() ) !== -1 ?
2351 this.active.nextAll( ".ui-menu-item" ) :
2354 // If no matches on the current filter, reset to the last character pressed
2355 // to move down the menu to the first item that starts with that character
2356 if ( !match.length ) {
2357 character = String.fromCharCode( event.keyCode );
2358 match = this._filterMenuItems( character );
2361 if ( match.length ) {
2362 this.focus( event, match );
2363 this.previousFilter = character;
2364 this.filterTimer = this._delay(function() {
2365 delete this.previousFilter;
2368 delete this.previousFilter;
2372 if ( preventDefault ) {
2373 event.preventDefault();
2377 _activate: function( event ) {
2378 if ( !this.active.is( ".ui-state-disabled" ) ) {
2379 if ( this.active.is( "[aria-haspopup='true']" ) ) {
2380 this.expand( event );
2382 this.select( event );
2387 refresh: function() {
2390 icon = this.options.icons.submenu,
2391 submenus = this.element.find( this.options.menus );
2393 this.element.toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length );
2395 // Initialize nested menus
2396 submenus.filter( ":not(.ui-menu)" )
2397 .addClass( "ui-menu ui-widget ui-widget-content ui-front" )
2400 role: this.options.role,
2401 "aria-hidden": "true",
2402 "aria-expanded": "false"
2405 var menu = $( this ),
2406 item = menu.parent(),
2407 submenuCarat = $( "<span>" )
2408 .addClass( "ui-menu-icon ui-icon " + icon )
2409 .data( "ui-menu-submenu-carat", true );
2412 .attr( "aria-haspopup", "true" )
2413 .prepend( submenuCarat );
2414 menu.attr( "aria-labelledby", item.attr( "id" ) );
2417 menus = submenus.add( this.element );
2418 items = menus.find( this.options.items );
2420 // Initialize menu-items containing spaces and/or dashes only as dividers
2421 items.not( ".ui-menu-item" ).each(function() {
2422 var item = $( this );
2423 if ( that._isDivider( item ) ) {
2424 item.addClass( "ui-widget-content ui-menu-divider" );
2428 // Don't refresh list items that are already adapted
2429 items.not( ".ui-menu-item, .ui-menu-divider" )
2430 .addClass( "ui-menu-item" )
2434 role: this._itemRole()
2437 // Add aria-disabled attribute to any disabled menu item
2438 items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
2440 // If the active item has been removed, blur the menu
2441 if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
2446 _itemRole: function() {
2450 }[ this.options.role ];
2453 _setOption: function( key, value ) {
2454 if ( key === "icons" ) {
2455 this.element.find( ".ui-menu-icon" )
2456 .removeClass( this.options.icons.submenu )
2457 .addClass( value.submenu );
2459 if ( key === "disabled" ) {
2461 .toggleClass( "ui-state-disabled", !!value )
2462 .attr( "aria-disabled", value );
2464 this._super( key, value );
2467 focus: function( event, item ) {
2468 var nested, focused;
2469 this.blur( event, event && event.type === "focus" );
2471 this._scrollIntoView( item );
2473 this.active = item.first();
2474 focused = this.active.addClass( "ui-state-focus" ).removeClass( "ui-state-active" );
2475 // Only update aria-activedescendant if there's a role
2476 // otherwise we assume focus is managed elsewhere
2477 if ( this.options.role ) {
2478 this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
2481 // Highlight active parent menu item, if any
2484 .closest( ".ui-menu-item" )
2485 .addClass( "ui-state-active" );
2487 if ( event && event.type === "keydown" ) {
2490 this.timer = this._delay(function() {
2495 nested = item.children( ".ui-menu" );
2496 if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) {
2497 this._startOpening(nested);
2499 this.activeMenu = item.parent();
2501 this._trigger( "focus", event, { item: item } );
2504 _scrollIntoView: function( item ) {
2505 var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
2506 if ( this._hasScroll() ) {
2507 borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0;
2508 paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0;
2509 offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
2510 scroll = this.activeMenu.scrollTop();
2511 elementHeight = this.activeMenu.height();
2512 itemHeight = item.outerHeight();
2515 this.activeMenu.scrollTop( scroll + offset );
2516 } else if ( offset + itemHeight > elementHeight ) {
2517 this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
2522 blur: function( event, fromFocus ) {
2524 clearTimeout( this.timer );
2527 if ( !this.active ) {
2531 this.active.removeClass( "ui-state-focus" );
2534 this._trigger( "blur", event, { item: this.active } );
2537 _startOpening: function( submenu ) {
2538 clearTimeout( this.timer );
2540 // Don't open if already open fixes a Firefox bug that caused a .5 pixel
2541 // shift in the submenu position when mousing over the carat icon
2542 if ( submenu.attr( "aria-hidden" ) !== "true" ) {
2546 this.timer = this._delay(function() {
2548 this._open( submenu );
2552 _open: function( submenu ) {
2553 var position = $.extend({
2555 }, this.options.position );
2557 clearTimeout( this.timer );
2558 this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
2560 .attr( "aria-hidden", "true" );
2564 .removeAttr( "aria-hidden" )
2565 .attr( "aria-expanded", "true" )
2566 .position( position );
2569 collapseAll: function( event, all ) {
2570 clearTimeout( this.timer );
2571 this.timer = this._delay(function() {
2572 // If we were passed an event, look for the submenu that contains the event
2573 var currentMenu = all ? this.element :
2574 $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
2576 // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway
2577 if ( !currentMenu.length ) {
2578 currentMenu = this.element;
2581 this._close( currentMenu );
2584 this.activeMenu = currentMenu;
2588 // With no arguments, closes the currently active menu - if nothing is active
2589 // it closes all menus. If passed an argument, it will search for menus BELOW
2590 _close: function( startMenu ) {
2592 startMenu = this.active ? this.active.parent() : this.element;
2598 .attr( "aria-hidden", "true" )
2599 .attr( "aria-expanded", "false" )
2601 .find( ".ui-state-active" ).not( ".ui-state-focus" )
2602 .removeClass( "ui-state-active" );
2605 _closeOnDocumentClick: function( event ) {
2606 return !$( event.target ).closest( ".ui-menu" ).length;
2609 _isDivider: function( item ) {
2611 // Match hyphen, em dash, en dash
2612 return !/[^\-\u2014\u2013\s]/.test( item.text() );
2615 collapse: function( event ) {
2616 var newItem = this.active &&
2617 this.active.parent().closest( ".ui-menu-item", this.element );
2618 if ( newItem && newItem.length ) {
2620 this.focus( event, newItem );
2624 expand: function( event ) {
2625 var newItem = this.active &&
2627 .children( ".ui-menu " )
2628 .find( this.options.items )
2631 if ( newItem && newItem.length ) {
2632 this._open( newItem.parent() );
2634 // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
2635 this._delay(function() {
2636 this.focus( event, newItem );
2641 next: function( event ) {
2642 this._move( "next", "first", event );
2645 previous: function( event ) {
2646 this._move( "prev", "last", event );
2649 isFirstItem: function() {
2650 return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
2653 isLastItem: function() {
2654 return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
2657 _move: function( direction, filter, event ) {
2659 if ( this.active ) {
2660 if ( direction === "first" || direction === "last" ) {
2662 [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
2666 [ direction + "All" ]( ".ui-menu-item" )
2670 if ( !next || !next.length || !this.active ) {
2671 next = this.activeMenu.find( this.options.items )[ filter ]();
2674 this.focus( event, next );
2677 nextPage: function( event ) {
2678 var item, base, height;
2680 if ( !this.active ) {
2684 if ( this.isLastItem() ) {
2687 if ( this._hasScroll() ) {
2688 base = this.active.offset().top;
2689 height = this.element.height();
2690 this.active.nextAll( ".ui-menu-item" ).each(function() {
2692 return item.offset().top - base - height < 0;
2695 this.focus( event, item );
2697 this.focus( event, this.activeMenu.find( this.options.items )
2698 [ !this.active ? "first" : "last" ]() );
2702 previousPage: function( event ) {
2703 var item, base, height;
2704 if ( !this.active ) {
2708 if ( this.isFirstItem() ) {
2711 if ( this._hasScroll() ) {
2712 base = this.active.offset().top;
2713 height = this.element.height();
2714 this.active.prevAll( ".ui-menu-item" ).each(function() {
2716 return item.offset().top - base + height > 0;
2719 this.focus( event, item );
2721 this.focus( event, this.activeMenu.find( this.options.items ).first() );
2725 _hasScroll: function() {
2726 return this.element.outerHeight() < this.element.prop( "scrollHeight" );
2729 select: function( event ) {
2730 // TODO: It should never be possible to not have an active item at this
2731 // point, but the tests don't trigger mouseenter before click.
2732 this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
2733 var ui = { item: this.active };
2734 if ( !this.active.has( ".ui-menu" ).length ) {
2735 this.collapseAll( event, true );
2737 this._trigger( "select", event, ui );
2740 _filterMenuItems: function(character) {
2741 var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ),
2742 regex = new RegExp( "^" + escapedCharacter, "i" );
2744 return this.activeMenu
2745 .find( this.options.items )
2747 // Only match on items, not dividers or other content (#10571)
2748 .filter( ".ui-menu-item" )
2749 .filter(function() {
2750 return regex.test( $.trim( $( this ).text() ) );
2757 * jQuery UI Autocomplete 1.11.3
2758 * http://jqueryui.com
2760 * Copyright jQuery Foundation and other contributors
2761 * Released under the MIT license.
2762 * http://jquery.org/license
2764 * http://api.jqueryui.com/autocomplete/
2768 $.widget( "ui.autocomplete", {
2770 defaultElement: "<input>",
2796 _create: function() {
2797 // Some browsers only repeat keydown events, not keypress events,
2798 // so we use the suppressKeyPress flag to determine if we've already
2799 // handled the keydown event. #7269
2800 // Unfortunately the code for & in keypress is the same as the up arrow,
2801 // so we use the suppressKeyPressRepeat flag to avoid handling keypress
2802 // events when we know the keydown event was used to modify the
2803 // search term. #7799
2804 var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
2805 nodeName = this.element[ 0 ].nodeName.toLowerCase(),
2806 isTextarea = nodeName === "textarea",
2807 isInput = nodeName === "input";
2810 // Textareas are always multi-line
2812 // Inputs are always single-line, even if inside a contentEditable element
2813 // IE also treats inputs as contentEditable
2815 // All other element types are determined by whether or not they're contentEditable
2816 this.element.prop( "isContentEditable" );
2818 this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
2819 this.isNewMenu = true;
2822 .addClass( "ui-autocomplete-input" )
2823 .attr( "autocomplete", "off" );
2825 this._on( this.element, {
2826 keydown: function( event ) {
2827 if ( this.element.prop( "readOnly" ) ) {
2828 suppressKeyPress = true;
2829 suppressInput = true;
2830 suppressKeyPressRepeat = true;
2834 suppressKeyPress = false;
2835 suppressInput = false;
2836 suppressKeyPressRepeat = false;
2837 var keyCode = $.ui.keyCode;
2838 switch ( event.keyCode ) {
2839 case keyCode.PAGE_UP:
2840 suppressKeyPress = true;
2841 this._move( "previousPage", event );
2843 case keyCode.PAGE_DOWN:
2844 suppressKeyPress = true;
2845 this._move( "nextPage", event );
2848 suppressKeyPress = true;
2849 this._keyEvent( "previous", event );
2852 suppressKeyPress = true;
2853 this._keyEvent( "next", event );
2856 // when menu is open and has focus
2857 if ( this.menu.active ) {
2858 // #6055 - Opera still allows the keypress to occur
2859 // which causes forms to submit
2860 suppressKeyPress = true;
2861 event.preventDefault();
2862 this.menu.select( event );
2866 if ( this.menu.active ) {
2867 this.menu.select( event );
2870 case keyCode.ESCAPE:
2871 if ( this.menu.element.is( ":visible" ) ) {
2872 if ( !this.isMultiLine ) {
2873 this._value( this.term );
2875 this.close( event );
2876 // Different browsers have different default behavior for escape
2877 // Single press can mean undo or clear
2878 // Double press in IE means clear the whole form
2879 event.preventDefault();
2883 suppressKeyPressRepeat = true;
2884 // search timeout should be triggered before the input value is changed
2885 this._searchTimeout( event );
2889 keypress: function( event ) {
2890 if ( suppressKeyPress ) {
2891 suppressKeyPress = false;
2892 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
2893 event.preventDefault();
2897 if ( suppressKeyPressRepeat ) {
2901 // replicate some key handlers to allow them to repeat in Firefox and Opera
2902 var keyCode = $.ui.keyCode;
2903 switch ( event.keyCode ) {
2904 case keyCode.PAGE_UP:
2905 this._move( "previousPage", event );
2907 case keyCode.PAGE_DOWN:
2908 this._move( "nextPage", event );
2911 this._keyEvent( "previous", event );
2914 this._keyEvent( "next", event );
2918 input: function( event ) {
2919 if ( suppressInput ) {
2920 suppressInput = false;
2921 event.preventDefault();
2924 this._searchTimeout( event );
2927 this.selectedItem = null;
2928 this.previous = this._value();
2930 blur: function( event ) {
2931 if ( this.cancelBlur ) {
2932 delete this.cancelBlur;
2936 clearTimeout( this.searching );
2937 this.close( event );
2938 this._change( event );
2943 this.menu = $( "<ul>" )
2944 .addClass( "ui-autocomplete ui-front" )
2945 .appendTo( this._appendTo() )
2947 // disable ARIA support, the live region takes care of that
2951 .menu( "instance" );
2953 this._on( this.menu.element, {
2954 mousedown: function( event ) {
2955 // prevent moving focus out of the text field
2956 event.preventDefault();
2958 // IE doesn't prevent moving focus even with event.preventDefault()
2959 // so we set a flag to know when we should ignore the blur event
2960 this.cancelBlur = true;
2961 this._delay(function() {
2962 delete this.cancelBlur;
2965 // clicking on the scrollbar causes focus to shift to the body
2966 // but we can't detect a mouseup or a click immediately afterward
2967 // so we have to track the next mousedown and close the menu if
2968 // the user clicks somewhere outside of the autocomplete
2969 var menuElement = this.menu.element[ 0 ];
2970 if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
2971 this._delay(function() {
2973 this.document.one( "mousedown", function( event ) {
2974 if ( event.target !== that.element[ 0 ] &&
2975 event.target !== menuElement &&
2976 !$.contains( menuElement, event.target ) ) {
2983 menufocus: function( event, ui ) {
2986 // Prevent accidental activation of menu items in Firefox (#7024 #9118)
2987 if ( this.isNewMenu ) {
2988 this.isNewMenu = false;
2989 if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
2992 this.document.one( "mousemove", function() {
2993 $( event.target ).trigger( event.originalEvent );
3000 item = ui.item.data( "ui-autocomplete-item" );
3001 if ( false !== this._trigger( "focus", event, { item: item } ) ) {
3002 // use value to match what will end up in the input, if it was a key event
3003 if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
3004 this._value( item.value );
3008 // Announce the value in the liveRegion
3009 label = ui.item.attr( "aria-label" ) || item.value;
3010 if ( label && $.trim( label ).length ) {
3011 this.liveRegion.children().hide();
3012 $( "<div>" ).text( label ).appendTo( this.liveRegion );
3015 menuselect: function( event, ui ) {
3016 var item = ui.item.data( "ui-autocomplete-item" ),
3017 previous = this.previous;
3019 // only trigger when focus was lost (click on menu)
3020 if ( this.element[ 0 ] !== this.document[ 0 ].activeElement ) {
3021 this.element.focus();
3022 this.previous = previous;
3023 // #6109 - IE triggers two focus events and the second
3024 // is asynchronous, so we need to reset the previous
3025 // term synchronously and asynchronously :-(
3026 this._delay(function() {
3027 this.previous = previous;
3028 this.selectedItem = item;
3032 if ( false !== this._trigger( "select", event, { item: item } ) ) {
3033 this._value( item.value );
3035 // reset the term after the select event
3036 // this allows custom select handling to work properly
3037 this.term = this._value();
3039 this.close( event );
3040 this.selectedItem = item;
3044 this.liveRegion = $( "<span>", {
3046 "aria-live": "assertive",
3047 "aria-relevant": "additions"
3049 .addClass( "ui-helper-hidden-accessible" )
3050 .appendTo( this.document[ 0 ].body );
3052 // turning off autocomplete prevents the browser from remembering the
3053 // value when navigating through history, so we re-enable autocomplete
3054 // if the page is unloaded before the widget is destroyed. #7790
3055 this._on( this.window, {
3056 beforeunload: function() {
3057 this.element.removeAttr( "autocomplete" );
3062 _destroy: function() {
3063 clearTimeout( this.searching );
3065 .removeClass( "ui-autocomplete-input" )
3066 .removeAttr( "autocomplete" );
3067 this.menu.element.remove();
3068 this.liveRegion.remove();
3071 _setOption: function( key, value ) {
3072 this._super( key, value );
3073 if ( key === "source" ) {
3076 if ( key === "appendTo" ) {
3077 this.menu.element.appendTo( this._appendTo() );
3079 if ( key === "disabled" && value && this.xhr ) {
3084 _appendTo: function() {
3085 var element = this.options.appendTo;
3088 element = element.jquery || element.nodeType ?
3090 this.document.find( element ).eq( 0 );
3093 if ( !element || !element[ 0 ] ) {
3094 element = this.element.closest( ".ui-front" );
3097 if ( !element.length ) {
3098 element = this.document[ 0 ].body;
3104 _initSource: function() {
3107 if ( $.isArray( this.options.source ) ) {
3108 array = this.options.source;
3109 this.source = function( request, response ) {
3110 response( $.ui.autocomplete.filter( array, request.term ) );
3112 } else if ( typeof this.options.source === "string" ) {
3113 url = this.options.source;
3114 this.source = function( request, response ) {
3122 success: function( data ) {
3131 this.source = this.options.source;
3135 _searchTimeout: function( event ) {
3136 clearTimeout( this.searching );
3137 this.searching = this._delay(function() {
3139 // Search if the value has changed, or if the user retypes the same value (see #7434)
3140 var equalValues = this.term === this._value(),
3141 menuVisible = this.menu.element.is( ":visible" ),
3142 modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
3144 if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) {
3145 this.selectedItem = null;
3146 this.search( null, event );
3148 }, this.options.delay );
3151 search: function( value, event ) {
3152 value = value != null ? value : this._value();
3154 // always save the actual value, not the one passed as an argument
3155 this.term = this._value();
3157 if ( value.length < this.options.minLength ) {
3158 return this.close( event );
3161 if ( this._trigger( "search", event ) === false ) {
3165 return this._search( value );
3168 _search: function( value ) {
3170 this.element.addClass( "ui-autocomplete-loading" );
3171 this.cancelSearch = false;
3173 this.source( { term: value }, this._response() );
3176 _response: function() {
3177 var index = ++this.requestIndex;
3179 return $.proxy(function( content ) {
3180 if ( index === this.requestIndex ) {
3181 this.__response( content );
3185 if ( !this.pending ) {
3186 this.element.removeClass( "ui-autocomplete-loading" );
3191 __response: function( content ) {
3193 content = this._normalize( content );
3195 this._trigger( "response", null, { content: content } );
3196 if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
3197 this._suggest( content );
3198 this._trigger( "open" );
3200 // use ._close() instead of .close() so we don't cancel future searches
3205 close: function( event ) {
3206 this.cancelSearch = true;
3207 this._close( event );
3210 _close: function( event ) {
3211 if ( this.menu.element.is( ":visible" ) ) {
3212 this.menu.element.hide();
3214 this.isNewMenu = true;
3215 this._trigger( "close", event );
3219 _change: function( event ) {
3220 if ( this.previous !== this._value() ) {
3221 this._trigger( "change", event, { item: this.selectedItem } );
3225 _normalize: function( items ) {
3226 // assume all items have the right format when the first item is complete
3227 if ( items.length && items[ 0 ].label && items[ 0 ].value ) {
3230 return $.map( items, function( item ) {
3231 if ( typeof item === "string" ) {
3237 return $.extend( {}, item, {
3238 label: item.label || item.value,
3239 value: item.value || item.label
3244 _suggest: function( items ) {
3245 var ul = this.menu.element.empty();
3246 this._renderMenu( ul, items );
3247 this.isNewMenu = true;
3248 this.menu.refresh();
3250 // size and position menu
3253 ul.position( $.extend({
3255 }, this.options.position ) );
3257 if ( this.options.autoFocus ) {
3262 _resizeMenu: function() {
3263 var ul = this.menu.element;
3264 ul.outerWidth( Math.max(
3265 // Firefox wraps long text (possibly a rounding bug)
3266 // so we add 1px to avoid the wrapping (#7513)
3267 ul.width( "" ).outerWidth() + 1,
3268 this.element.outerWidth()
3272 _renderMenu: function( ul, items ) {
3274 $.each( items, function( index, item ) {
3275 that._renderItemData( ul, item );
3279 _renderItemData: function( ul, item ) {
3280 return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
3283 _renderItem: function( ul, item ) {
3284 return $( "<li>" ).text( item.label ).appendTo( ul );
3287 _move: function( direction, event ) {
3288 if ( !this.menu.element.is( ":visible" ) ) {
3289 this.search( null, event );
3292 if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
3293 this.menu.isLastItem() && /^next/.test( direction ) ) {
3295 if ( !this.isMultiLine ) {
3296 this._value( this.term );
3302 this.menu[ direction ]( event );
3305 widget: function() {
3306 return this.menu.element;
3309 _value: function() {
3310 return this.valueMethod.apply( this.element, arguments );
3313 _keyEvent: function( keyEvent, event ) {
3314 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
3315 this._move( keyEvent, event );
3317 // prevents moving cursor to beginning/end of the text field in some browsers
3318 event.preventDefault();
3323 $.extend( $.ui.autocomplete, {
3324 escapeRegex: function( value ) {
3325 return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
3327 filter: function( array, term ) {
3328 var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" );
3329 return $.grep( array, function( value ) {
3330 return matcher.test( value.label || value.value || value );
3335 // live region extension, adding a `messages` option
3336 // NOTE: This is an experimental API. We are still investigating
3337 // a full solution for string manipulation and internationalization.
3338 $.widget( "ui.autocomplete", $.ui.autocomplete, {
3341 noResults: "No search results.",
3342 results: function( amount ) {
3343 return amount + ( amount > 1 ? " results are" : " result is" ) +
3344 " available, use up and down arrow keys to navigate.";
3349 __response: function( content ) {
3351 this._superApply( arguments );
3352 if ( this.options.disabled || this.cancelSearch ) {
3355 if ( content && content.length ) {
3356 message = this.options.messages.results( content.length );
3358 message = this.options.messages.noResults;
3360 this.liveRegion.children().hide();
3361 $( "<div>" ).text( message ).appendTo( this.liveRegion );
3365 var autocomplete = $.ui.autocomplete;
3369 * jQuery UI Button 1.11.3
3370 * http://jqueryui.com
3372 * Copyright jQuery Foundation and other contributors
3373 * Released under the MIT license.
3374 * http://jquery.org/license
3376 * http://api.jqueryui.com/button/
3381 baseClasses = "ui-button ui-widget ui-state-default ui-corner-all",
3382 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",
3383 formResetHandler = function() {
3384 var form = $( this );
3385 setTimeout(function() {
3386 form.find( ":ui-button" ).button( "refresh" );
3389 radioGroup = function( radio ) {
3390 var name = radio.name,
3394 name = name.replace( /'/g, "\\'" );
3396 radios = $( form ).find( "[name='" + name + "'][type=radio]" );
3398 radios = $( "[name='" + name + "'][type=radio]", radio.ownerDocument )
3399 .filter(function() {
3407 $.widget( "ui.button", {
3409 defaultElement: "<button>",
3419 _create: function() {
3420 this.element.closest( "form" )
3421 .unbind( "reset" + this.eventNamespace )
3422 .bind( "reset" + this.eventNamespace, formResetHandler );
3424 if ( typeof this.options.disabled !== "boolean" ) {
3425 this.options.disabled = !!this.element.prop( "disabled" );
3427 this.element.prop( "disabled", this.options.disabled );
3430 this._determineButtonType();
3431 this.hasTitle = !!this.buttonElement.attr( "title" );
3434 options = this.options,
3435 toggleButton = this.type === "checkbox" || this.type === "radio",
3436 activeClass = !toggleButton ? "ui-state-active" : "";
3438 if ( options.label === null ) {
3439 options.label = (this.type === "input" ? this.buttonElement.val() : this.buttonElement.html());
3442 this._hoverable( this.buttonElement );
3445 .addClass( baseClasses )
3446 .attr( "role", "button" )
3447 .bind( "mouseenter" + this.eventNamespace, function() {
3448 if ( options.disabled ) {
3451 if ( this === lastActive ) {
3452 $( this ).addClass( "ui-state-active" );
3455 .bind( "mouseleave" + this.eventNamespace, function() {
3456 if ( options.disabled ) {
3459 $( this ).removeClass( activeClass );
3461 .bind( "click" + this.eventNamespace, function( event ) {
3462 if ( options.disabled ) {
3463 event.preventDefault();
3464 event.stopImmediatePropagation();
3468 // Can't use _focusable() because the element that receives focus
3469 // and the element that gets the ui-state-focus class are different
3472 this.buttonElement.addClass( "ui-state-focus" );
3475 this.buttonElement.removeClass( "ui-state-focus" );
3479 if ( toggleButton ) {
3480 this.element.bind( "change" + this.eventNamespace, function() {
3485 if ( this.type === "checkbox" ) {
3486 this.buttonElement.bind( "click" + this.eventNamespace, function() {
3487 if ( options.disabled ) {
3491 } else if ( this.type === "radio" ) {
3492 this.buttonElement.bind( "click" + this.eventNamespace, function() {
3493 if ( options.disabled ) {
3496 $( this ).addClass( "ui-state-active" );
3497 that.buttonElement.attr( "aria-pressed", "true" );
3499 var radio = that.element[ 0 ];
3503 return $( this ).button( "widget" )[ 0 ];
3505 .removeClass( "ui-state-active" )
3506 .attr( "aria-pressed", "false" );
3510 .bind( "mousedown" + this.eventNamespace, function() {
3511 if ( options.disabled ) {
3514 $( this ).addClass( "ui-state-active" );
3516 that.document.one( "mouseup", function() {
3520 .bind( "mouseup" + this.eventNamespace, function() {
3521 if ( options.disabled ) {
3524 $( this ).removeClass( "ui-state-active" );
3526 .bind( "keydown" + this.eventNamespace, function(event) {
3527 if ( options.disabled ) {
3530 if ( event.keyCode === $.ui.keyCode.SPACE || event.keyCode === $.ui.keyCode.ENTER ) {
3531 $( this ).addClass( "ui-state-active" );
3534 // see #8559, we bind to blur here in case the button element loses
3535 // focus between keydown and keyup, it would be left in an "active" state
3536 .bind( "keyup" + this.eventNamespace + " blur" + this.eventNamespace, function() {
3537 $( this ).removeClass( "ui-state-active" );
3540 if ( this.buttonElement.is("a") ) {
3541 this.buttonElement.keyup(function(event) {
3542 if ( event.keyCode === $.ui.keyCode.SPACE ) {
3543 // TODO pass through original event correctly (just as 2nd argument doesn't work)
3550 this._setOption( "disabled", options.disabled );
3551 this._resetButton();
3554 _determineButtonType: function() {
3555 var ancestor, labelSelector, checked;
3557 if ( this.element.is("[type=checkbox]") ) {
3558 this.type = "checkbox";
3559 } else if ( this.element.is("[type=radio]") ) {
3560 this.type = "radio";
3561 } else if ( this.element.is("input") ) {
3562 this.type = "input";
3564 this.type = "button";
3567 if ( this.type === "checkbox" || this.type === "radio" ) {
3568 // we don't search against the document in case the element
3569 // is disconnected from the DOM
3570 ancestor = this.element.parents().last();
3571 labelSelector = "label[for='" + this.element.attr("id") + "']";
3572 this.buttonElement = ancestor.find( labelSelector );
3573 if ( !this.buttonElement.length ) {
3574 ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings();
3575 this.buttonElement = ancestor.filter( labelSelector );
3576 if ( !this.buttonElement.length ) {
3577 this.buttonElement = ancestor.find( labelSelector );
3580 this.element.addClass( "ui-helper-hidden-accessible" );
3582 checked = this.element.is( ":checked" );
3584 this.buttonElement.addClass( "ui-state-active" );
3586 this.buttonElement.prop( "aria-pressed", checked );
3588 this.buttonElement = this.element;
3592 widget: function() {
3593 return this.buttonElement;
3596 _destroy: function() {
3598 .removeClass( "ui-helper-hidden-accessible" );
3600 .removeClass( baseClasses + " ui-state-active " + typeClasses )
3601 .removeAttr( "role" )
3602 .removeAttr( "aria-pressed" )
3603 .html( this.buttonElement.find(".ui-button-text").html() );
3605 if ( !this.hasTitle ) {
3606 this.buttonElement.removeAttr( "title" );
3610 _setOption: function( key, value ) {
3611 this._super( key, value );
3612 if ( key === "disabled" ) {
3613 this.widget().toggleClass( "ui-state-disabled", !!value );
3614 this.element.prop( "disabled", !!value );
3616 if ( this.type === "checkbox" || this.type === "radio" ) {
3617 this.buttonElement.removeClass( "ui-state-focus" );
3619 this.buttonElement.removeClass( "ui-state-focus ui-state-active" );
3624 this._resetButton();
3627 refresh: function() {
3629 var isDisabled = this.element.is( "input, button" ) ? this.element.is( ":disabled" ) : this.element.hasClass( "ui-button-disabled" );
3631 if ( isDisabled !== this.options.disabled ) {
3632 this._setOption( "disabled", isDisabled );
3634 if ( this.type === "radio" ) {
3635 radioGroup( this.element[0] ).each(function() {
3636 if ( $( this ).is( ":checked" ) ) {
3637 $( this ).button( "widget" )
3638 .addClass( "ui-state-active" )
3639 .attr( "aria-pressed", "true" );
3641 $( this ).button( "widget" )
3642 .removeClass( "ui-state-active" )
3643 .attr( "aria-pressed", "false" );
3646 } else if ( this.type === "checkbox" ) {
3647 if ( this.element.is( ":checked" ) ) {
3649 .addClass( "ui-state-active" )
3650 .attr( "aria-pressed", "true" );
3653 .removeClass( "ui-state-active" )
3654 .attr( "aria-pressed", "false" );
3659 _resetButton: function() {
3660 if ( this.type === "input" ) {
3661 if ( this.options.label ) {
3662 this.element.val( this.options.label );
3666 var buttonElement = this.buttonElement.removeClass( typeClasses ),
3667 buttonText = $( "<span></span>", this.document[0] )
3668 .addClass( "ui-button-text" )
3669 .html( this.options.label )
3670 .appendTo( buttonElement.empty() )
3672 icons = this.options.icons,
3673 multipleIcons = icons.primary && icons.secondary,
3676 if ( icons.primary || icons.secondary ) {
3677 if ( this.options.text ) {
3678 buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) );
3681 if ( icons.primary ) {
3682 buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" );
3685 if ( icons.secondary ) {
3686 buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" );
3689 if ( !this.options.text ) {
3690 buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" );
3692 if ( !this.hasTitle ) {
3693 buttonElement.attr( "title", $.trim( buttonText ) );
3697 buttonClasses.push( "ui-button-text-only" );
3699 buttonElement.addClass( buttonClasses.join( " " ) );
3703 $.widget( "ui.buttonset", {
3706 items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)"
3709 _create: function() {
3710 this.element.addClass( "ui-buttonset" );
3717 _setOption: function( key, value ) {
3718 if ( key === "disabled" ) {
3719 this.buttons.button( "option", key, value );
3722 this._super( key, value );
3725 refresh: function() {
3726 var rtl = this.element.css( "direction" ) === "rtl",
3727 allButtons = this.element.find( this.options.items ),
3728 existingButtons = allButtons.filter( ":ui-button" );
3730 // Initialize new buttons
3731 allButtons.not( ":ui-button" ).button();
3733 // Refresh existing buttons
3734 existingButtons.button( "refresh" );
3736 this.buttons = allButtons
3738 return $( this ).button( "widget" )[ 0 ];
3740 .removeClass( "ui-corner-all ui-corner-left ui-corner-right" )
3742 .addClass( rtl ? "ui-corner-right" : "ui-corner-left" )
3745 .addClass( rtl ? "ui-corner-left" : "ui-corner-right" )
3750 _destroy: function() {
3751 this.element.removeClass( "ui-buttonset" );
3754 return $( this ).button( "widget" )[ 0 ];
3756 .removeClass( "ui-corner-left ui-corner-right" )
3758 .button( "destroy" );
3762 var button = $.ui.button;
3766 * jQuery UI Datepicker 1.11.3
3767 * http://jqueryui.com
3769 * Copyright jQuery Foundation and other contributors
3770 * Released under the MIT license.
3771 * http://jquery.org/license
3773 * http://api.jqueryui.com/datepicker/
3777 $.extend($.ui, { datepicker: { version: "1.11.3" } });
3779 var datepicker_instActive;
3781 function datepicker_getZindex( elem ) {
3782 var position, value;
3783 while ( elem.length && elem[ 0 ] !== document ) {
3784 // Ignore z-index if position is set to a value where z-index is ignored by the browser
3785 // This makes behavior of this function consistent across browsers
3786 // WebKit always returns auto if the element is positioned
3787 position = elem.css( "position" );
3788 if ( position === "absolute" || position === "relative" || position === "fixed" ) {
3789 // IE returns 0 when zIndex is not specified
3790 // other browsers return a string
3791 // we ignore the case of nested elements with an explicit value of 0
3792 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
3793 value = parseInt( elem.css( "zIndex" ), 10 );
3794 if ( !isNaN( value ) && value !== 0 ) {
3798 elem = elem.parent();
3803 /* Date picker manager.
3804 Use the singleton instance of this class, $.datepicker, to interact with the date picker.
3805 Settings for (groups of) date pickers are maintained in an instance object,
3806 allowing multiple different settings on the same page. */
3808 function Datepicker() {
3809 this._curInst = null; // The current instance in use
3810 this._keyEvent = false; // If the last event was a key event
3811 this._disabledInputs = []; // List of date picker inputs that have been disabled
3812 this._datepickerShowing = false; // True if the popup picker is showing , false if not
3813 this._inDialog = false; // True if showing within a "dialog", false if not
3814 this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
3815 this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
3816 this._appendClass = "ui-datepicker-append"; // The name of the append marker class
3817 this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
3818 this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
3819 this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
3820 this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
3821 this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
3822 this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
3823 this.regional = []; // Available regional settings, indexed by language code
3824 this.regional[""] = { // Default regional settings
3825 closeText: "Done", // Display text for close link
3826 prevText: "Prev", // Display text for previous month link
3827 nextText: "Next", // Display text for next month link
3828 currentText: "Today", // Display text for current month link
3829 monthNames: ["January","February","March","April","May","June",
3830 "July","August","September","October","November","December"], // Names of months for drop-down and formatting
3831 monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting
3832 dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting
3833 dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting
3834 dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday
3835 weekHeader: "Wk", // Column header for week of the year
3836 dateFormat: "mm/dd/yy", // See format options on parseDate
3837 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
3838 isRTL: false, // True if right-to-left language, false if left-to-right
3839 showMonthAfterYear: false, // True if the year select precedes month, false for month then year
3840 yearSuffix: "" // Additional text to append to the year in the month headers
3842 this._defaults = { // Global defaults for all the date picker instances
3843 showOn: "focus", // "focus" for popup on focus,
3844 // "button" for trigger button, or "both" for either
3845 showAnim: "fadeIn", // Name of jQuery animation for popup
3846 showOptions: {}, // Options for enhanced animations
3847 defaultDate: null, // Used when field is blank: actual date,
3848 // +/-number for offset from today, null for today
3849 appendText: "", // Display text following the input box, e.g. showing the format
3850 buttonText: "...", // Text for trigger button
3851 buttonImage: "", // URL for trigger button image
3852 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
3853 hideIfNoPrevNext: false, // True to hide next/previous month links
3854 // if not applicable, false to just disable them
3855 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
3856 gotoCurrent: false, // True if today link goes back to current selection instead
3857 changeMonth: false, // True if month can be selected directly, false if only prev/next
3858 changeYear: false, // True if year can be selected directly, false if only prev/next
3859 yearRange: "c-10:c+10", // Range of years to display in drop-down,
3860 // either relative to today's year (-nn:+nn), relative to currently displayed year
3861 // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
3862 showOtherMonths: false, // True to show dates in other months, false to leave blank
3863 selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
3864 showWeek: false, // True to show week of the year, false to not show it
3865 calculateWeek: this.iso8601Week, // How to calculate the week of the year,
3866 // takes a Date and returns the number of the week for it
3867 shortYearCutoff: "+10", // Short year values < this are in the current century,
3868 // > this are in the previous century,
3869 // string value starting with "+" for current year + value
3870 minDate: null, // The earliest selectable date, or null for no limit
3871 maxDate: null, // The latest selectable date, or null for no limit
3872 duration: "fast", // Duration of display/closure
3873 beforeShowDay: null, // Function that takes a date and returns an array with
3874 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
3875 // [2] = cell title (optional), e.g. $.datepicker.noWeekends
3876 beforeShow: null, // Function that takes an input field and
3877 // returns a set of custom settings for the date picker
3878 onSelect: null, // Define a callback function when a date is selected
3879 onChangeMonthYear: null, // Define a callback function when the month or year is changed
3880 onClose: null, // Define a callback function when the datepicker is closed
3881 numberOfMonths: 1, // Number of months to show at a time
3882 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
3883 stepMonths: 1, // Number of months to step back/forward
3884 stepBigMonths: 12, // Number of months to step back/forward for the big links
3885 altField: "", // Selector for an alternate field to store selected dates into
3886 altFormat: "", // The date format to use for the alternate field
3887 constrainInput: true, // The input is constrained by the current date format
3888 showButtonPanel: false, // True to show button panel, false to not show it
3889 autoSize: false, // True to size the input for the date format, false to leave as is
3890 disabled: false // The initial disabled state
3892 $.extend(this._defaults, this.regional[""]);
3893 this.regional.en = $.extend( true, {}, this.regional[ "" ]);
3894 this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en );
3895 this.dpDiv = datepicker_bindHover($("<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"));
3898 $.extend(Datepicker.prototype, {
3899 /* Class name added to elements to indicate already configured with a date picker. */
3900 markerClassName: "hasDatepicker",
3902 //Keep track of the maximum number of rows displayed (see #7043)
3905 // TODO rename to "widget" when switching to widget factory
3906 _widgetDatepicker: function() {
3910 /* Override the default settings for all instances of the date picker.
3911 * @param settings object - the new settings to use as defaults (anonymous object)
3912 * @return the manager object
3914 setDefaults: function(settings) {
3915 datepicker_extendRemove(this._defaults, settings || {});
3919 /* Attach the date picker to a jQuery selection.
3920 * @param target element - the target input field or division or span
3921 * @param settings object - the new settings to use for this date picker instance (anonymous)
3923 _attachDatepicker: function(target, settings) {
3924 var nodeName, inline, inst;
3925 nodeName = target.nodeName.toLowerCase();
3926 inline = (nodeName === "div" || nodeName === "span");
3929 target.id = "dp" + this.uuid;
3931 inst = this._newInst($(target), inline);
3932 inst.settings = $.extend({}, settings || {});
3933 if (nodeName === "input") {
3934 this._connectDatepicker(target, inst);
3935 } else if (inline) {
3936 this._inlineDatepicker(target, inst);
3940 /* Create a new instance object. */
3941 _newInst: function(target, inline) {
3942 var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars
3943 return {id: id, input: target, // associated target
3944 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
3945 drawMonth: 0, drawYear: 0, // month being drawn
3946 inline: inline, // is datepicker inline or not
3947 dpDiv: (!inline ? this.dpDiv : // presentation div
3948 datepicker_bindHover($("<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))};
3951 /* Attach the date picker to an input field. */
3952 _connectDatepicker: function(target, inst) {
3953 var input = $(target);
3954 inst.append = $([]);
3955 inst.trigger = $([]);
3956 if (input.hasClass(this.markerClassName)) {
3959 this._attachments(input, inst);
3960 input.addClass(this.markerClassName).keydown(this._doKeyDown).
3961 keypress(this._doKeyPress).keyup(this._doKeyUp);
3962 this._autoSize(inst);
3963 $.data(target, "datepicker", inst);
3964 //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
3965 if( inst.settings.disabled ) {
3966 this._disableDatepicker( target );
3970 /* Make attachments based on settings. */
3971 _attachments: function(input, inst) {
3972 var showOn, buttonText, buttonImage,
3973 appendText = this._get(inst, "appendText"),
3974 isRTL = this._get(inst, "isRTL");
3977 inst.append.remove();
3980 inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>");
3981 input[isRTL ? "before" : "after"](inst.append);
3984 input.unbind("focus", this._showDatepicker);
3987 inst.trigger.remove();
3990 showOn = this._get(inst, "showOn");
3991 if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field
3992 input.focus(this._showDatepicker);
3994 if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked
3995 buttonText = this._get(inst, "buttonText");
3996 buttonImage = this._get(inst, "buttonImage");
3997 inst.trigger = $(this._get(inst, "buttonImageOnly") ?
3998 $("<img/>").addClass(this._triggerClass).
3999 attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
4000 $("<button type='button'></button>").addClass(this._triggerClass).
4001 html(!buttonImage ? buttonText : $("<img/>").attr(
4002 { src:buttonImage, alt:buttonText, title:buttonText })));
4003 input[isRTL ? "before" : "after"](inst.trigger);
4004 inst.trigger.click(function() {
4005 if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) {
4006 $.datepicker._hideDatepicker();
4007 } else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) {
4008 $.datepicker._hideDatepicker();
4009 $.datepicker._showDatepicker(input[0]);
4011 $.datepicker._showDatepicker(input[0]);
4018 /* Apply the maximum length for the date format. */
4019 _autoSize: function(inst) {
4020 if (this._get(inst, "autoSize") && !inst.inline) {
4021 var findMax, max, maxI, i,
4022 date = new Date(2009, 12 - 1, 20), // Ensure double digits
4023 dateFormat = this._get(inst, "dateFormat");
4025 if (dateFormat.match(/[DM]/)) {
4026 findMax = function(names) {
4029 for (i = 0; i < names.length; i++) {
4030 if (names[i].length > max) {
4031 max = names[i].length;
4037 date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
4038 "monthNames" : "monthNamesShort"))));
4039 date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
4040 "dayNames" : "dayNamesShort"))) + 20 - date.getDay());
4042 inst.input.attr("size", this._formatDate(inst, date).length);
4046 /* Attach an inline date picker to a div. */
4047 _inlineDatepicker: function(target, inst) {
4048 var divSpan = $(target);
4049 if (divSpan.hasClass(this.markerClassName)) {
4052 divSpan.addClass(this.markerClassName).append(inst.dpDiv);
4053 $.data(target, "datepicker", inst);
4054 this._setDate(inst, this._getDefaultDate(inst), true);
4055 this._updateDatepicker(inst);
4056 this._updateAlternate(inst);
4057 //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
4058 if( inst.settings.disabled ) {
4059 this._disableDatepicker( target );
4061 // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
4062 // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
4063 inst.dpDiv.css( "display", "block" );
4066 /* Pop-up the date picker in a "dialog" box.
4067 * @param input element - ignored
4068 * @param date string or Date - the initial date to display
4069 * @param onSelect function - the function to call when a date is selected
4070 * @param settings object - update the dialog date picker instance's settings (anonymous object)
4071 * @param pos int[2] - coordinates for the dialog's position within the screen or
4072 * event - with x/y coordinates or
4073 * leave empty for default (screen centre)
4074 * @return the manager object
4076 _dialogDatepicker: function(input, date, onSelect, settings, pos) {
4077 var id, browserWidth, browserHeight, scrollX, scrollY,
4078 inst = this._dialogInst; // internal instance
4082 id = "dp" + this.uuid;
4083 this._dialogInput = $("<input type='text' id='" + id +
4084 "' style='position: absolute; top: -100px; width: 0px;'/>");
4085 this._dialogInput.keydown(this._doKeyDown);
4086 $("body").append(this._dialogInput);
4087 inst = this._dialogInst = this._newInst(this._dialogInput, false);
4089 $.data(this._dialogInput[0], "datepicker", inst);
4091 datepicker_extendRemove(inst.settings, settings || {});
4092 date = (date && date.constructor === Date ? this._formatDate(inst, date) : date);
4093 this._dialogInput.val(date);
4095 this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
4097 browserWidth = document.documentElement.clientWidth;
4098 browserHeight = document.documentElement.clientHeight;
4099 scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
4100 scrollY = document.documentElement.scrollTop || document.body.scrollTop;
4101 this._pos = // should use actual width/height below
4102 [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
4105 // move input on screen for focus, but hidden behind dialog
4106 this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px");
4107 inst.settings.onSelect = onSelect;
4108 this._inDialog = true;
4109 this.dpDiv.addClass(this._dialogClass);
4110 this._showDatepicker(this._dialogInput[0]);
4112 $.blockUI(this.dpDiv);
4114 $.data(this._dialogInput[0], "datepicker", inst);
4118 /* Detach a datepicker from its control.
4119 * @param target element - the target input field or division or span
4121 _destroyDatepicker: function(target) {
4123 $target = $(target),
4124 inst = $.data(target, "datepicker");
4126 if (!$target.hasClass(this.markerClassName)) {
4130 nodeName = target.nodeName.toLowerCase();
4131 $.removeData(target, "datepicker");
4132 if (nodeName === "input") {
4133 inst.append.remove();
4134 inst.trigger.remove();
4135 $target.removeClass(this.markerClassName).
4136 unbind("focus", this._showDatepicker).
4137 unbind("keydown", this._doKeyDown).
4138 unbind("keypress", this._doKeyPress).
4139 unbind("keyup", this._doKeyUp);
4140 } else if (nodeName === "div" || nodeName === "span") {
4141 $target.removeClass(this.markerClassName).empty();
4144 if ( datepicker_instActive === inst ) {
4145 datepicker_instActive = null;
4149 /* Enable the date picker to a jQuery selection.
4150 * @param target element - the target input field or division or span
4152 _enableDatepicker: function(target) {
4153 var nodeName, inline,
4154 $target = $(target),
4155 inst = $.data(target, "datepicker");
4157 if (!$target.hasClass(this.markerClassName)) {
4161 nodeName = target.nodeName.toLowerCase();
4162 if (nodeName === "input") {
4163 target.disabled = false;
4164 inst.trigger.filter("button").
4165 each(function() { this.disabled = false; }).end().
4166 filter("img").css({opacity: "1.0", cursor: ""});
4167 } else if (nodeName === "div" || nodeName === "span") {
4168 inline = $target.children("." + this._inlineClass);
4169 inline.children().removeClass("ui-state-disabled");
4170 inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
4171 prop("disabled", false);
4173 this._disabledInputs = $.map(this._disabledInputs,
4174 function(value) { return (value === target ? null : value); }); // delete entry
4177 /* Disable the date picker to a jQuery selection.
4178 * @param target element - the target input field or division or span
4180 _disableDatepicker: function(target) {
4181 var nodeName, inline,
4182 $target = $(target),
4183 inst = $.data(target, "datepicker");
4185 if (!$target.hasClass(this.markerClassName)) {
4189 nodeName = target.nodeName.toLowerCase();
4190 if (nodeName === "input") {
4191 target.disabled = true;
4192 inst.trigger.filter("button").
4193 each(function() { this.disabled = true; }).end().
4194 filter("img").css({opacity: "0.5", cursor: "default"});
4195 } else if (nodeName === "div" || nodeName === "span") {
4196 inline = $target.children("." + this._inlineClass);
4197 inline.children().addClass("ui-state-disabled");
4198 inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
4199 prop("disabled", true);
4201 this._disabledInputs = $.map(this._disabledInputs,
4202 function(value) { return (value === target ? null : value); }); // delete entry
4203 this._disabledInputs[this._disabledInputs.length] = target;
4206 /* Is the first field in a jQuery collection disabled as a datepicker?
4207 * @param target element - the target input field or division or span
4208 * @return boolean - true if disabled, false if enabled
4210 _isDisabledDatepicker: function(target) {
4214 for (var i = 0; i < this._disabledInputs.length; i++) {
4215 if (this._disabledInputs[i] === target) {
4222 /* Retrieve the instance data for the target control.
4223 * @param target element - the target input field or division or span
4224 * @return object - the associated instance data
4225 * @throws error if a jQuery problem getting data
4227 _getInst: function(target) {
4229 return $.data(target, "datepicker");
4232 throw "Missing instance data for this datepicker";
4236 /* Update or retrieve the settings for a date picker attached to an input field or division.
4237 * @param target element - the target input field or division or span
4238 * @param name object - the new settings to update or
4239 * string - the name of the setting to change or retrieve,
4240 * when retrieving also "all" for all instance settings or
4241 * "defaults" for all global defaults
4242 * @param value any - the new value for the setting
4243 * (omit if above is an object or to retrieve a value)
4245 _optionDatepicker: function(target, name, value) {
4246 var settings, date, minDate, maxDate,
4247 inst = this._getInst(target);
4249 if (arguments.length === 2 && typeof name === "string") {
4250 return (name === "defaults" ? $.extend({}, $.datepicker._defaults) :
4251 (inst ? (name === "all" ? $.extend({}, inst.settings) :
4252 this._get(inst, name)) : null));
4255 settings = name || {};
4256 if (typeof name === "string") {
4258 settings[name] = value;
4262 if (this._curInst === inst) {
4263 this._hideDatepicker();
4266 date = this._getDateDatepicker(target, true);
4267 minDate = this._getMinMaxDate(inst, "min");
4268 maxDate = this._getMinMaxDate(inst, "max");
4269 datepicker_extendRemove(inst.settings, settings);
4270 // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
4271 if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) {
4272 inst.settings.minDate = this._formatDate(inst, minDate);
4274 if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) {
4275 inst.settings.maxDate = this._formatDate(inst, maxDate);
4277 if ( "disabled" in settings ) {
4278 if ( settings.disabled ) {
4279 this._disableDatepicker(target);
4281 this._enableDatepicker(target);
4284 this._attachments($(target), inst);
4285 this._autoSize(inst);
4286 this._setDate(inst, date);
4287 this._updateAlternate(inst);
4288 this._updateDatepicker(inst);
4292 // change method deprecated
4293 _changeDatepicker: function(target, name, value) {
4294 this._optionDatepicker(target, name, value);
4297 /* Redraw the date picker attached to an input field or division.
4298 * @param target element - the target input field or division or span
4300 _refreshDatepicker: function(target) {
4301 var inst = this._getInst(target);
4303 this._updateDatepicker(inst);
4307 /* Set the dates for a jQuery selection.
4308 * @param target element - the target input field or division or span
4309 * @param date Date - the new date
4311 _setDateDatepicker: function(target, date) {
4312 var inst = this._getInst(target);
4314 this._setDate(inst, date);
4315 this._updateDatepicker(inst);
4316 this._updateAlternate(inst);
4320 /* Get the date(s) for the first entry in a jQuery selection.
4321 * @param target element - the target input field or division or span
4322 * @param noDefault boolean - true if no default date is to be used
4323 * @return Date - the current date
4325 _getDateDatepicker: function(target, noDefault) {
4326 var inst = this._getInst(target);
4327 if (inst && !inst.inline) {
4328 this._setDateFromField(inst, noDefault);
4330 return (inst ? this._getDate(inst) : null);
4333 /* Handle keystrokes. */
4334 _doKeyDown: function(event) {
4335 var onSelect, dateStr, sel,
4336 inst = $.datepicker._getInst(event.target),
4338 isRTL = inst.dpDiv.is(".ui-datepicker-rtl");
4340 inst._keyEvent = true;
4341 if ($.datepicker._datepickerShowing) {
4342 switch (event.keyCode) {
4343 case 9: $.datepicker._hideDatepicker();
4345 break; // hide on tab out
4346 case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." +
4347 $.datepicker._currentClass + ")", inst.dpDiv);
4349 $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
4352 onSelect = $.datepicker._get(inst, "onSelect");
4354 dateStr = $.datepicker._formatDate(inst);
4356 // trigger custom callback
4357 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);
4359 $.datepicker._hideDatepicker();
4362 return false; // don't submit the form
4363 case 27: $.datepicker._hideDatepicker();
4364 break; // hide on escape
4365 case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
4366 -$.datepicker._get(inst, "stepBigMonths") :
4367 -$.datepicker._get(inst, "stepMonths")), "M");
4368 break; // previous month/year on page up/+ ctrl
4369 case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
4370 +$.datepicker._get(inst, "stepBigMonths") :
4371 +$.datepicker._get(inst, "stepMonths")), "M");
4372 break; // next month/year on page down/+ ctrl
4373 case 35: if (event.ctrlKey || event.metaKey) {
4374 $.datepicker._clearDate(event.target);
4376 handled = event.ctrlKey || event.metaKey;
4377 break; // clear on ctrl or command +end
4378 case 36: if (event.ctrlKey || event.metaKey) {
4379 $.datepicker._gotoToday(event.target);
4381 handled = event.ctrlKey || event.metaKey;
4382 break; // current on ctrl or command +home
4383 case 37: if (event.ctrlKey || event.metaKey) {
4384 $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D");
4386 handled = event.ctrlKey || event.metaKey;
4387 // -1 day on ctrl or command +left
4388 if (event.originalEvent.altKey) {
4389 $.datepicker._adjustDate(event.target, (event.ctrlKey ?
4390 -$.datepicker._get(inst, "stepBigMonths") :
4391 -$.datepicker._get(inst, "stepMonths")), "M");
4393 // next month/year on alt +left on Mac
4395 case 38: if (event.ctrlKey || event.metaKey) {
4396 $.datepicker._adjustDate(event.target, -7, "D");
4398 handled = event.ctrlKey || event.metaKey;
4399 break; // -1 week on ctrl or command +up
4400 case 39: if (event.ctrlKey || event.metaKey) {
4401 $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D");
4403 handled = event.ctrlKey || event.metaKey;
4404 // +1 day on ctrl or command +right
4405 if (event.originalEvent.altKey) {
4406 $.datepicker._adjustDate(event.target, (event.ctrlKey ?
4407 +$.datepicker._get(inst, "stepBigMonths") :
4408 +$.datepicker._get(inst, "stepMonths")), "M");
4410 // next month/year on alt +right
4412 case 40: if (event.ctrlKey || event.metaKey) {
4413 $.datepicker._adjustDate(event.target, +7, "D");
4415 handled = event.ctrlKey || event.metaKey;
4416 break; // +1 week on ctrl or command +down
4417 default: handled = false;
4419 } else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home
4420 $.datepicker._showDatepicker(this);
4426 event.preventDefault();
4427 event.stopPropagation();
4431 /* Filter entered characters - based on date format. */
4432 _doKeyPress: function(event) {
4434 inst = $.datepicker._getInst(event.target);
4436 if ($.datepicker._get(inst, "constrainInput")) {
4437 chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat"));
4438 chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode);
4439 return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1);
4443 /* Synchronise manual entry and field/alternate field. */
4444 _doKeyUp: function(event) {
4446 inst = $.datepicker._getInst(event.target);
4448 if (inst.input.val() !== inst.lastVal) {
4450 date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
4451 (inst.input ? inst.input.val() : null),
4452 $.datepicker._getFormatConfig(inst));
4454 if (date) { // only if valid
4455 $.datepicker._setDateFromField(inst);
4456 $.datepicker._updateAlternate(inst);
4457 $.datepicker._updateDatepicker(inst);
4466 /* Pop-up the date picker for a given input field.
4467 * If false returned from beforeShow event handler do not show.
4468 * @param input element - the input field attached to the date picker or
4469 * event - if triggered by focus
4471 _showDatepicker: function(input) {
4472 input = input.target || input;
4473 if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger
4474 input = $("input", input.parentNode)[0];
4477 if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here
4481 var inst, beforeShow, beforeShowSettings, isFixed,
4482 offset, showAnim, duration;
4484 inst = $.datepicker._getInst(input);
4485 if ($.datepicker._curInst && $.datepicker._curInst !== inst) {
4486 $.datepicker._curInst.dpDiv.stop(true, true);
4487 if ( inst && $.datepicker._datepickerShowing ) {
4488 $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );
4492 beforeShow = $.datepicker._get(inst, "beforeShow");
4493 beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
4494 if(beforeShowSettings === false){
4497 datepicker_extendRemove(inst.settings, beforeShowSettings);
4499 inst.lastVal = null;
4500 $.datepicker._lastInput = input;
4501 $.datepicker._setDateFromField(inst);
4503 if ($.datepicker._inDialog) { // hide cursor
4506 if (!$.datepicker._pos) { // position below input
4507 $.datepicker._pos = $.datepicker._findPos(input);
4508 $.datepicker._pos[1] += input.offsetHeight; // add the height
4512 $(input).parents().each(function() {
4513 isFixed |= $(this).css("position") === "fixed";
4517 offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
4518 $.datepicker._pos = null;
4519 //to avoid flashes on Firefox
4521 // determine sizing offscreen
4522 inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"});
4523 $.datepicker._updateDatepicker(inst);
4524 // fix width for dynamic number of date pickers
4525 // and adjust position before showing
4526 offset = $.datepicker._checkOffset(inst, offset, isFixed);
4527 inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
4528 "static" : (isFixed ? "fixed" : "absolute")), display: "none",
4529 left: offset.left + "px", top: offset.top + "px"});
4532 showAnim = $.datepicker._get(inst, "showAnim");
4533 duration = $.datepicker._get(inst, "duration");
4534 inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 );
4535 $.datepicker._datepickerShowing = true;
4537 if ( $.effects && $.effects.effect[ showAnim ] ) {
4538 inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration);
4540 inst.dpDiv[showAnim || "show"](showAnim ? duration : null);
4543 if ( $.datepicker._shouldFocusInput( inst ) ) {
4547 $.datepicker._curInst = inst;
4551 /* Generate the date picker content. */
4552 _updateDatepicker: function(inst) {
4553 this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
4554 datepicker_instActive = inst; // for delegate hover events
4555 inst.dpDiv.empty().append(this._generateHTML(inst));
4556 this._attachHandlers(inst);
4559 numMonths = this._getNumberOfMonths(inst),
4560 cols = numMonths[1],
4562 activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" );
4564 if ( activeCell.length > 0 ) {
4565 datepicker_handleMouseover.apply( activeCell.get( 0 ) );
4568 inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");
4570 inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em");
4572 inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") +
4573 "Class"]("ui-datepicker-multi");
4574 inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") +
4575 "Class"]("ui-datepicker-rtl");
4577 if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
4581 // deffered render of the years select (to avoid flashes on Firefox)
4582 if( inst.yearshtml ){
4583 origyearshtml = inst.yearshtml;
4584 setTimeout(function(){
4585 //assure that inst.yearshtml didn't change.
4586 if( origyearshtml === inst.yearshtml && inst.yearshtml ){
4587 inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml);
4589 origyearshtml = inst.yearshtml = null;
4594 // #6694 - don't focus the input if it's already focused
4595 // this breaks the change event in IE
4596 // Support: IE and jQuery <1.9
4597 _shouldFocusInput: function( inst ) {
4598 return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
4601 /* Check positioning to remain on screen. */
4602 _checkOffset: function(inst, offset, isFixed) {
4603 var dpWidth = inst.dpDiv.outerWidth(),
4604 dpHeight = inst.dpDiv.outerHeight(),
4605 inputWidth = inst.input ? inst.input.outerWidth() : 0,
4606 inputHeight = inst.input ? inst.input.outerHeight() : 0,
4607 viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()),
4608 viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop());
4610 offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0);
4611 offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0;
4612 offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
4614 // now check if datepicker is showing outside window viewport - move to a better place if so.
4615 offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
4616 Math.abs(offset.left + dpWidth - viewWidth) : 0);
4617 offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
4618 Math.abs(dpHeight + inputHeight) : 0);
4623 /* Find an object's position on the screen. */
4624 _findPos: function(obj) {
4626 inst = this._getInst(obj),
4627 isRTL = this._get(inst, "isRTL");
4629 while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) {
4630 obj = obj[isRTL ? "previousSibling" : "nextSibling"];
4633 position = $(obj).offset();
4634 return [position.left, position.top];
4637 /* Hide the date picker from view.
4638 * @param input element - the input field attached to the date picker
4640 _hideDatepicker: function(input) {
4641 var showAnim, duration, postProcess, onClose,
4642 inst = this._curInst;
4644 if (!inst || (input && inst !== $.data(input, "datepicker"))) {
4648 if (this._datepickerShowing) {
4649 showAnim = this._get(inst, "showAnim");
4650 duration = this._get(inst, "duration");
4651 postProcess = function() {
4652 $.datepicker._tidyDialog(inst);
4655 // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
4656 if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
4657 inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess);
4659 inst.dpDiv[(showAnim === "slideDown" ? "slideUp" :
4660 (showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess);
4666 this._datepickerShowing = false;
4668 onClose = this._get(inst, "onClose");
4670 onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]);
4673 this._lastInput = null;
4674 if (this._inDialog) {
4675 this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" });
4678 $("body").append(this.dpDiv);
4681 this._inDialog = false;
4685 /* Tidy up after a dialog display. */
4686 _tidyDialog: function(inst) {
4687 inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar");
4690 /* Close date picker if clicked elsewhere. */
4691 _checkExternalClick: function(event) {
4692 if (!$.datepicker._curInst) {
4696 var $target = $(event.target),
4697 inst = $.datepicker._getInst($target[0]);
4699 if ( ( ( $target[0].id !== $.datepicker._mainDivId &&
4700 $target.parents("#" + $.datepicker._mainDivId).length === 0 &&
4701 !$target.hasClass($.datepicker.markerClassName) &&
4702 !$target.closest("." + $.datepicker._triggerClass).length &&
4703 $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) ||
4704 ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) {
4705 $.datepicker._hideDatepicker();
4709 /* Adjust one of the date sub-fields. */
4710 _adjustDate: function(id, offset, period) {
4712 inst = this._getInst(target[0]);
4714 if (this._isDisabledDatepicker(target[0])) {
4717 this._adjustInstDate(inst, offset +
4718 (period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning
4720 this._updateDatepicker(inst);
4723 /* Action for current link. */
4724 _gotoToday: function(id) {
4727 inst = this._getInst(target[0]);
4729 if (this._get(inst, "gotoCurrent") && inst.currentDay) {
4730 inst.selectedDay = inst.currentDay;
4731 inst.drawMonth = inst.selectedMonth = inst.currentMonth;
4732 inst.drawYear = inst.selectedYear = inst.currentYear;
4735 inst.selectedDay = date.getDate();
4736 inst.drawMonth = inst.selectedMonth = date.getMonth();
4737 inst.drawYear = inst.selectedYear = date.getFullYear();
4739 this._notifyChange(inst);
4740 this._adjustDate(target);
4743 /* Action for selecting a new month/year. */
4744 _selectMonthYear: function(id, select, period) {
4746 inst = this._getInst(target[0]);
4748 inst["selected" + (period === "M" ? "Month" : "Year")] =
4749 inst["draw" + (period === "M" ? "Month" : "Year")] =
4750 parseInt(select.options[select.selectedIndex].value,10);
4752 this._notifyChange(inst);
4753 this._adjustDate(target);
4756 /* Action for selecting a day. */
4757 _selectDay: function(id, month, year, td) {
4761 if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
4765 inst = this._getInst(target[0]);
4766 inst.selectedDay = inst.currentDay = $("a", td).html();
4767 inst.selectedMonth = inst.currentMonth = month;
4768 inst.selectedYear = inst.currentYear = year;
4769 this._selectDate(id, this._formatDate(inst,
4770 inst.currentDay, inst.currentMonth, inst.currentYear));
4773 /* Erase the input field and hide the date picker. */
4774 _clearDate: function(id) {
4776 this._selectDate(target, "");
4779 /* Update the input field with the selected date. */
4780 _selectDate: function(id, dateStr) {
4783 inst = this._getInst(target[0]);
4785 dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
4787 inst.input.val(dateStr);
4789 this._updateAlternate(inst);
4791 onSelect = this._get(inst, "onSelect");
4793 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
4794 } else if (inst.input) {
4795 inst.input.trigger("change"); // fire the change event
4799 this._updateDatepicker(inst);
4801 this._hideDatepicker();
4802 this._lastInput = inst.input[0];
4803 if (typeof(inst.input[0]) !== "object") {
4804 inst.input.focus(); // restore focus
4806 this._lastInput = null;
4810 /* Update any alternate field to synchronise with the main field. */
4811 _updateAlternate: function(inst) {
4812 var altFormat, date, dateStr,
4813 altField = this._get(inst, "altField");
4815 if (altField) { // update alternate field too
4816 altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat");
4817 date = this._getDate(inst);
4818 dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
4819 $(altField).each(function() { $(this).val(dateStr); });
4823 /* Set as beforeShowDay function to prevent selection of weekends.
4824 * @param date Date - the date to customise
4825 * @return [boolean, string] - is this date selectable?, what is its CSS class?
4827 noWeekends: function(date) {
4828 var day = date.getDay();
4829 return [(day > 0 && day < 6), ""];
4832 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
4833 * @param date Date - the date to get the week for
4834 * @return number - the number of the week within the year that contains this date
4836 iso8601Week: function(date) {
4838 checkDate = new Date(date.getTime());
4840 // Find Thursday of this week starting on Monday
4841 checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
4843 time = checkDate.getTime();
4844 checkDate.setMonth(0); // Compare with Jan 1
4845 checkDate.setDate(1);
4846 return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
4849 /* Parse a string value into a date object.
4850 * See formatDate below for the possible formats.
4852 * @param format string - the expected format of the date
4853 * @param value string - the date in the above format
4854 * @param settings Object - attributes include:
4855 * shortYearCutoff number - the cutoff year for determining the century (optional)
4856 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
4857 * dayNames string[7] - names of the days from Sunday (optional)
4858 * monthNamesShort string[12] - abbreviated names of the months (optional)
4859 * monthNames string[12] - names of the months (optional)
4860 * @return Date - the extracted date value or null if value is blank
4862 parseDate: function (format, value, settings) {
4863 if (format == null || value == null) {
4864 throw "Invalid arguments";
4867 value = (typeof value === "object" ? value.toString() : value + "");
4872 var iFormat, dim, extra,
4874 shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff,
4875 shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
4876 new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)),
4877 dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
4878 dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
4879 monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
4880 monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
4887 // Check whether a format character is doubled
4888 lookAhead = function(match) {
4889 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
4895 // Extract a number from the string value
4896 getNumber = function(match) {
4897 var isDoubled = lookAhead(match),
4898 size = (match === "@" ? 14 : (match === "!" ? 20 :
4899 (match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))),
4900 minSize = (match === "y" ? size : 1),
4901 digits = new RegExp("^\\d{" + minSize + "," + size + "}"),
4902 num = value.substring(iValue).match(digits);
4904 throw "Missing number at position " + iValue;
4906 iValue += num[0].length;
4907 return parseInt(num[0], 10);
4909 // Extract a name from the string value and convert to an index
4910 getName = function(match, shortNames, longNames) {
4912 names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {
4914 }).sort(function (a, b) {
4915 return -(a[1].length - b[1].length);
4918 $.each(names, function (i, pair) {
4920 if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) {
4922 iValue += name.length;
4929 throw "Unknown name at position " + iValue;
4932 // Confirm that a literal character matches the string value
4933 checkLiteral = function() {
4934 if (value.charAt(iValue) !== format.charAt(iFormat)) {
4935 throw "Unexpected literal at position " + iValue;
4940 for (iFormat = 0; iFormat < format.length; iFormat++) {
4942 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
4948 switch (format.charAt(iFormat)) {
4950 day = getNumber("d");
4953 getName("D", dayNamesShort, dayNames);
4956 doy = getNumber("o");
4959 month = getNumber("m");
4962 month = getName("M", monthNamesShort, monthNames);
4965 year = getNumber("y");
4968 date = new Date(getNumber("@"));
4969 year = date.getFullYear();
4970 month = date.getMonth() + 1;
4971 day = date.getDate();
4974 date = new Date((getNumber("!") - this._ticksTo1970) / 10000);
4975 year = date.getFullYear();
4976 month = date.getMonth() + 1;
4977 day = date.getDate();
4980 if (lookAhead("'")){
4992 if (iValue < value.length){
4993 extra = value.substr(iValue);
4994 if (!/^\s+/.test(extra)) {
4995 throw "Extra/unparsed characters found in date: " + extra;
5000 year = new Date().getFullYear();
5001 } else if (year < 100) {
5002 year += new Date().getFullYear() - new Date().getFullYear() % 100 +
5003 (year <= shortYearCutoff ? 0 : -100);
5010 dim = this._getDaysInMonth(year, month - 1);
5019 date = this._daylightSavingAdjust(new Date(year, month - 1, day));
5020 if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) {
5021 throw "Invalid date"; // E.g. 31/02/00
5026 /* Standard date formats. */
5027 ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
5028 COOKIE: "D, dd M yy",
5029 ISO_8601: "yy-mm-dd",
5030 RFC_822: "D, d M y",
5031 RFC_850: "DD, dd-M-y",
5032 RFC_1036: "D, d M y",
5033 RFC_1123: "D, d M yy",
5034 RFC_2822: "D, d M yy",
5035 RSS: "D, d M y", // RFC 822
5038 W3C: "yy-mm-dd", // ISO 8601
5040 _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
5041 Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
5043 /* Format a date object into a string value.
5044 * The format can be combinations of the following:
5045 * d - day of month (no leading zero)
5046 * dd - day of month (two digit)
5047 * o - day of year (no leading zeros)
5048 * oo - day of year (three digit)
5049 * D - day name short
5050 * DD - day name long
5051 * m - month of year (no leading zero)
5052 * mm - month of year (two digit)
5053 * M - month name short
5054 * MM - month name long
5055 * y - year (two digit)
5056 * yy - year (four digit)
5057 * @ - Unix timestamp (ms since 01/01/1970)
5058 * ! - Windows ticks (100ns since 01/01/0001)
5059 * "..." - literal text
5062 * @param format string - the desired format of the date
5063 * @param date Date - the date value to format
5064 * @param settings Object - attributes include:
5065 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
5066 * dayNames string[7] - names of the days from Sunday (optional)
5067 * monthNamesShort string[12] - abbreviated names of the months (optional)
5068 * monthNames string[12] - names of the months (optional)
5069 * @return string - the date in the above format
5071 formatDate: function (format, date, settings) {
5077 dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
5078 dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
5079 monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
5080 monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
5081 // Check whether a format character is doubled
5082 lookAhead = function(match) {
5083 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
5089 // Format a number, with leading zero if necessary
5090 formatNumber = function(match, value, len) {
5091 var num = "" + value;
5092 if (lookAhead(match)) {
5093 while (num.length < len) {
5099 // Format a name, short or long as requested
5100 formatName = function(match, value, shortNames, longNames) {
5101 return (lookAhead(match) ? longNames[value] : shortNames[value]);
5107 for (iFormat = 0; iFormat < format.length; iFormat++) {
5109 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
5112 output += format.charAt(iFormat);
5115 switch (format.charAt(iFormat)) {
5117 output += formatNumber("d", date.getDate(), 2);
5120 output += formatName("D", date.getDay(), dayNamesShort, dayNames);
5123 output += formatNumber("o",
5124 Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);
5127 output += formatNumber("m", date.getMonth() + 1, 2);
5130 output += formatName("M", date.getMonth(), monthNamesShort, monthNames);
5133 output += (lookAhead("y") ? date.getFullYear() :
5134 (date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100);
5137 output += date.getTime();
5140 output += date.getTime() * 10000 + this._ticksTo1970;
5143 if (lookAhead("'")) {
5150 output += format.charAt(iFormat);
5158 /* Extract all possible characters from the date format. */
5159 _possibleChars: function (format) {
5163 // Check whether a format character is doubled
5164 lookAhead = function(match) {
5165 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
5172 for (iFormat = 0; iFormat < format.length; iFormat++) {
5174 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
5177 chars += format.charAt(iFormat);
5180 switch (format.charAt(iFormat)) {
5181 case "d": case "m": case "y": case "@":
5182 chars += "0123456789";
5185 return null; // Accept anything
5187 if (lookAhead("'")) {
5194 chars += format.charAt(iFormat);
5201 /* Get a setting value, defaulting if necessary. */
5202 _get: function(inst, name) {
5203 return inst.settings[name] !== undefined ?
5204 inst.settings[name] : this._defaults[name];
5207 /* Parse existing date and initialise date picker. */
5208 _setDateFromField: function(inst, noDefault) {
5209 if (inst.input.val() === inst.lastVal) {
5213 var dateFormat = this._get(inst, "dateFormat"),
5214 dates = inst.lastVal = inst.input ? inst.input.val() : null,
5215 defaultDate = this._getDefaultDate(inst),
5217 settings = this._getFormatConfig(inst);
5220 date = this.parseDate(dateFormat, dates, settings) || defaultDate;
5222 dates = (noDefault ? "" : dates);
5224 inst.selectedDay = date.getDate();
5225 inst.drawMonth = inst.selectedMonth = date.getMonth();
5226 inst.drawYear = inst.selectedYear = date.getFullYear();
5227 inst.currentDay = (dates ? date.getDate() : 0);
5228 inst.currentMonth = (dates ? date.getMonth() : 0);
5229 inst.currentYear = (dates ? date.getFullYear() : 0);
5230 this._adjustInstDate(inst);
5233 /* Retrieve the default date shown on opening. */
5234 _getDefaultDate: function(inst) {
5235 return this._restrictMinMax(inst,
5236 this._determineDate(inst, this._get(inst, "defaultDate"), new Date()));
5239 /* A date may be specified as an exact value or a relative one. */
5240 _determineDate: function(inst, date, defaultDate) {
5241 var offsetNumeric = function(offset) {
5242 var date = new Date();
5243 date.setDate(date.getDate() + offset);
5246 offsetString = function(offset) {
5248 return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
5249 offset, $.datepicker._getFormatConfig(inst));
5255 var date = (offset.toLowerCase().match(/^c/) ?
5256 $.datepicker._getDate(inst) : null) || new Date(),
5257 year = date.getFullYear(),
5258 month = date.getMonth(),
5259 day = date.getDate(),
5260 pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
5261 matches = pattern.exec(offset);
5264 switch (matches[2] || "d") {
5265 case "d" : case "D" :
5266 day += parseInt(matches[1],10); break;
5267 case "w" : case "W" :
5268 day += parseInt(matches[1],10) * 7; break;
5269 case "m" : case "M" :
5270 month += parseInt(matches[1],10);
5271 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
5273 case "y": case "Y" :
5274 year += parseInt(matches[1],10);
5275 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
5278 matches = pattern.exec(offset);
5280 return new Date(year, month, day);
5282 newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) :
5283 (typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));
5285 newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate);
5287 newDate.setHours(0);
5288 newDate.setMinutes(0);
5289 newDate.setSeconds(0);
5290 newDate.setMilliseconds(0);
5292 return this._daylightSavingAdjust(newDate);
5295 /* Handle switch to/from daylight saving.
5296 * Hours may be non-zero on daylight saving cut-over:
5297 * > 12 when midnight changeover, but then cannot generate
5298 * midnight datetime, so jump to 1AM, otherwise reset.
5299 * @param date (Date) the date to check
5300 * @return (Date) the corrected date
5302 _daylightSavingAdjust: function(date) {
5306 date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
5310 /* Set the date(s) directly. */
5311 _setDate: function(inst, date, noChange) {
5313 origMonth = inst.selectedMonth,
5314 origYear = inst.selectedYear,
5315 newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
5317 inst.selectedDay = inst.currentDay = newDate.getDate();
5318 inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
5319 inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
5320 if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) {
5321 this._notifyChange(inst);
5323 this._adjustInstDate(inst);
5325 inst.input.val(clear ? "" : this._formatDate(inst));
5329 /* Retrieve the date(s) directly. */
5330 _getDate: function(inst) {
5331 var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null :
5332 this._daylightSavingAdjust(new Date(
5333 inst.currentYear, inst.currentMonth, inst.currentDay)));
5337 /* Attach the onxxx handlers. These are declared statically so
5338 * they work with static code transformers like Caja.
5340 _attachHandlers: function(inst) {
5341 var stepMonths = this._get(inst, "stepMonths"),
5342 id = "#" + inst.id.replace( /\\\\/g, "\\" );
5343 inst.dpDiv.find("[data-handler]").map(function () {
5346 $.datepicker._adjustDate(id, -stepMonths, "M");
5349 $.datepicker._adjustDate(id, +stepMonths, "M");
5352 $.datepicker._hideDatepicker();
5354 today: function () {
5355 $.datepicker._gotoToday(id);
5357 selectDay: function () {
5358 $.datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this);
5361 selectMonth: function () {
5362 $.datepicker._selectMonthYear(id, this, "M");
5365 selectYear: function () {
5366 $.datepicker._selectMonthYear(id, this, "Y");
5370 $(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]);
5374 /* Generate the HTML for the current state of the date picker. */
5375 _generateHTML: function(inst) {
5376 var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
5377 controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
5378 monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
5379 selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
5380 cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
5381 printDate, dRow, tbody, daySettings, otherMonth, unselectable,
5382 tempDate = new Date(),
5383 today = this._daylightSavingAdjust(
5384 new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time
5385 isRTL = this._get(inst, "isRTL"),
5386 showButtonPanel = this._get(inst, "showButtonPanel"),
5387 hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"),
5388 navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"),
5389 numMonths = this._getNumberOfMonths(inst),
5390 showCurrentAtPos = this._get(inst, "showCurrentAtPos"),
5391 stepMonths = this._get(inst, "stepMonths"),
5392 isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1),
5393 currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
5394 new Date(inst.currentYear, inst.currentMonth, inst.currentDay))),
5395 minDate = this._getMinMaxDate(inst, "min"),
5396 maxDate = this._getMinMaxDate(inst, "max"),
5397 drawMonth = inst.drawMonth - showCurrentAtPos,
5398 drawYear = inst.drawYear;
5400 if (drawMonth < 0) {
5405 maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
5406 maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
5407 maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
5408 while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
5410 if (drawMonth < 0) {
5416 inst.drawMonth = drawMonth;
5417 inst.drawYear = drawYear;
5419 prevText = this._get(inst, "prevText");
5420 prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
5421 this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
5422 this._getFormatConfig(inst)));
5424 prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
5425 "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
5426 " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" :
5427 (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>"));
5429 nextText = this._get(inst, "nextText");
5430 nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
5431 this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
5432 this._getFormatConfig(inst)));
5434 next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
5435 "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
5436 " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" :
5437 (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>"));
5439 currentText = this._get(inst, "currentText");
5440 gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today);
5441 currentText = (!navigationAsDateFormat ? currentText :
5442 this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
5444 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'>" +
5445 this._get(inst, "closeText") + "</button>" : "");
5447 buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") +
5448 (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'" +
5449 ">" + currentText + "</button>" : "") + (isRTL ? "" : controls) + "</div>" : "";
5451 firstDay = parseInt(this._get(inst, "firstDay"),10);
5452 firstDay = (isNaN(firstDay) ? 0 : firstDay);
5454 showWeek = this._get(inst, "showWeek");
5455 dayNames = this._get(inst, "dayNames");
5456 dayNamesMin = this._get(inst, "dayNamesMin");
5457 monthNames = this._get(inst, "monthNames");
5458 monthNamesShort = this._get(inst, "monthNamesShort");
5459 beforeShowDay = this._get(inst, "beforeShowDay");
5460 showOtherMonths = this._get(inst, "showOtherMonths");
5461 selectOtherMonths = this._get(inst, "selectOtherMonths");
5462 defaultDate = this._getDefaultDate(inst);
5465 for (row = 0; row < numMonths[0]; row++) {
5468 for (col = 0; col < numMonths[1]; col++) {
5469 selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
5470 cornerClass = " ui-corner-all";
5473 calender += "<div class='ui-datepicker-group";
5474 if (numMonths[1] > 1) {
5476 case 0: calender += " ui-datepicker-group-first";
5477 cornerClass = " ui-corner-" + (isRTL ? "right" : "left"); break;
5478 case numMonths[1]-1: calender += " ui-datepicker-group-last";
5479 cornerClass = " ui-corner-" + (isRTL ? "left" : "right"); break;
5480 default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
5485 calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
5486 (/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") +
5487 (/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") +
5488 this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
5489 row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
5490 "</div><table class='ui-datepicker-calendar'><thead>" +
5492 thead = (showWeek ? "<th class='ui-datepicker-week-col'>" + this._get(inst, "weekHeader") + "</th>" : "");
5493 for (dow = 0; dow < 7; dow++) { // days of the week
5494 day = (dow + firstDay) % 7;
5495 thead += "<th scope='col'" + ((dow + firstDay + 6) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "") + ">" +
5496 "<span title='" + dayNames[day] + "'>" + dayNamesMin[day] + "</span></th>";
5498 calender += thead + "</tr></thead><tbody>";
5499 daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
5500 if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) {
5501 inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
5503 leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
5504 curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate
5505 numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043)
5506 this.maxRows = numRows;
5507 printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
5508 for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows
5510 tbody = (!showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
5511 this._get(inst, "calculateWeek")(printDate) + "</td>");
5512 for (dow = 0; dow < 7; dow++) { // create date picker days
5513 daySettings = (beforeShowDay ?
5514 beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]);
5515 otherMonth = (printDate.getMonth() !== drawMonth);
5516 unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
5517 (minDate && printDate < minDate) || (maxDate && printDate > maxDate);
5518 tbody += "<td class='" +
5519 ((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends
5520 (otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months
5521 ((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key
5522 (defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ?
5523 // or defaultDate is current printedDate and defaultDate is selectedDate
5524 " " + this._dayOverClass : "") + // highlight selected day
5525 (unselectable ? " " + this._unselectableClass + " ui-state-disabled": "") + // highlight unselectable days
5526 (otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates
5527 (printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day
5528 (printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different)
5529 ((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "'") + "'" : "") + // cell title
5530 (unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions
5531 (otherMonth && !showOtherMonths ? " " : // display for other months
5532 (unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
5533 (printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") +
5534 (printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day
5535 (otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months
5536 "' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date
5537 printDate.setDate(printDate.getDate() + 1);
5538 printDate = this._daylightSavingAdjust(printDate);
5540 calender += tbody + "</tr>";
5543 if (drawMonth > 11) {
5547 calender += "</tbody></table>" + (isMultiMonth ? "</div>" +
5548 ((numMonths[0] > 0 && col === numMonths[1]-1) ? "<div class='ui-datepicker-row-break'></div>" : "") : "");
5553 html += buttonPanel;
5554 inst._keyEvent = false;
5558 /* Generate the month and year header. */
5559 _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
5560 secondary, monthNames, monthNamesShort) {
5562 var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
5563 changeMonth = this._get(inst, "changeMonth"),
5564 changeYear = this._get(inst, "changeYear"),
5565 showMonthAfterYear = this._get(inst, "showMonthAfterYear"),
5566 html = "<div class='ui-datepicker-title'>",
5570 if (secondary || !changeMonth) {
5571 monthHtml += "<span class='ui-datepicker-month'>" + monthNames[drawMonth] + "</span>";
5573 inMinYear = (minDate && minDate.getFullYear() === drawYear);
5574 inMaxYear = (maxDate && maxDate.getFullYear() === drawYear);
5575 monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
5576 for ( month = 0; month < 12; month++) {
5577 if ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) {
5578 monthHtml += "<option value='" + month + "'" +
5579 (month === drawMonth ? " selected='selected'" : "") +
5580 ">" + monthNamesShort[month] + "</option>";
5583 monthHtml += "</select>";
5586 if (!showMonthAfterYear) {
5587 html += monthHtml + (secondary || !(changeMonth && changeYear) ? " " : "");
5591 if ( !inst.yearshtml ) {
5592 inst.yearshtml = "";
5593 if (secondary || !changeYear) {
5594 html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
5596 // determine range of years to display
5597 years = this._get(inst, "yearRange").split(":");
5598 thisYear = new Date().getFullYear();
5599 determineYear = function(value) {
5600 var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) :
5601 (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) :
5602 parseInt(value, 10)));
5603 return (isNaN(year) ? thisYear : year);
5605 year = determineYear(years[0]);
5606 endYear = Math.max(year, determineYear(years[1] || ""));
5607 year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
5608 endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
5609 inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
5610 for (; year <= endYear; year++) {
5611 inst.yearshtml += "<option value='" + year + "'" +
5612 (year === drawYear ? " selected='selected'" : "") +
5613 ">" + year + "</option>";
5615 inst.yearshtml += "</select>";
5617 html += inst.yearshtml;
5618 inst.yearshtml = null;
5622 html += this._get(inst, "yearSuffix");
5623 if (showMonthAfterYear) {
5624 html += (secondary || !(changeMonth && changeYear) ? " " : "") + monthHtml;
5626 html += "</div>"; // Close datepicker_header
5630 /* Adjust one of the date sub-fields. */
5631 _adjustInstDate: function(inst, offset, period) {
5632 var year = inst.drawYear + (period === "Y" ? offset : 0),
5633 month = inst.drawMonth + (period === "M" ? offset : 0),
5634 day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0),
5635 date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day)));
5637 inst.selectedDay = date.getDate();
5638 inst.drawMonth = inst.selectedMonth = date.getMonth();
5639 inst.drawYear = inst.selectedYear = date.getFullYear();
5640 if (period === "M" || period === "Y") {
5641 this._notifyChange(inst);
5645 /* Ensure a date is within any min/max bounds. */
5646 _restrictMinMax: function(inst, date) {
5647 var minDate = this._getMinMaxDate(inst, "min"),
5648 maxDate = this._getMinMaxDate(inst, "max"),
5649 newDate = (minDate && date < minDate ? minDate : date);
5650 return (maxDate && newDate > maxDate ? maxDate : newDate);
5653 /* Notify change of month/year. */
5654 _notifyChange: function(inst) {
5655 var onChange = this._get(inst, "onChangeMonthYear");
5657 onChange.apply((inst.input ? inst.input[0] : null),
5658 [inst.selectedYear, inst.selectedMonth + 1, inst]);
5662 /* Determine the number of months to show. */
5663 _getNumberOfMonths: function(inst) {
5664 var numMonths = this._get(inst, "numberOfMonths");
5665 return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths));
5668 /* Determine the current maximum date - ensure no time components are set. */
5669 _getMinMaxDate: function(inst, minMax) {
5670 return this._determineDate(inst, this._get(inst, minMax + "Date"), null);
5673 /* Find the number of days in a given month. */
5674 _getDaysInMonth: function(year, month) {
5675 return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();
5678 /* Find the day of the week of the first of a month. */
5679 _getFirstDayOfMonth: function(year, month) {
5680 return new Date(year, month, 1).getDay();
5683 /* Determines if we should allow a "next/prev" month display change. */
5684 _canAdjustMonth: function(inst, offset, curYear, curMonth) {
5685 var numMonths = this._getNumberOfMonths(inst),
5686 date = this._daylightSavingAdjust(new Date(curYear,
5687 curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
5690 date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
5692 return this._isInRange(inst, date);
5695 /* Is the given date in the accepted range? */
5696 _isInRange: function(inst, date) {
5697 var yearSplit, currentYear,
5698 minDate = this._getMinMaxDate(inst, "min"),
5699 maxDate = this._getMinMaxDate(inst, "max"),
5702 years = this._get(inst, "yearRange");
5704 yearSplit = years.split(":");
5705 currentYear = new Date().getFullYear();
5706 minYear = parseInt(yearSplit[0], 10);
5707 maxYear = parseInt(yearSplit[1], 10);
5708 if ( yearSplit[0].match(/[+\-].*/) ) {
5709 minYear += currentYear;
5711 if ( yearSplit[1].match(/[+\-].*/) ) {
5712 maxYear += currentYear;
5716 return ((!minDate || date.getTime() >= minDate.getTime()) &&
5717 (!maxDate || date.getTime() <= maxDate.getTime()) &&
5718 (!minYear || date.getFullYear() >= minYear) &&
5719 (!maxYear || date.getFullYear() <= maxYear));
5722 /* Provide the configuration settings for formatting/parsing. */
5723 _getFormatConfig: function(inst) {
5724 var shortYearCutoff = this._get(inst, "shortYearCutoff");
5725 shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff :
5726 new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
5727 return {shortYearCutoff: shortYearCutoff,
5728 dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"),
5729 monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")};
5732 /* Format the given date for display. */
5733 _formatDate: function(inst, day, month, year) {
5735 inst.currentDay = inst.selectedDay;
5736 inst.currentMonth = inst.selectedMonth;
5737 inst.currentYear = inst.selectedYear;
5739 var date = (day ? (typeof day === "object" ? day :
5740 this._daylightSavingAdjust(new Date(year, month, day))) :
5741 this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
5742 return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst));
5747 * Bind hover events for datepicker elements.
5748 * Done via delegate so the binding only occurs once in the lifetime of the parent div.
5749 * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
5751 function datepicker_bindHover(dpDiv) {
5752 var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
5753 return dpDiv.delegate(selector, "mouseout", function() {
5754 $(this).removeClass("ui-state-hover");
5755 if (this.className.indexOf("ui-datepicker-prev") !== -1) {
5756 $(this).removeClass("ui-datepicker-prev-hover");
5758 if (this.className.indexOf("ui-datepicker-next") !== -1) {
5759 $(this).removeClass("ui-datepicker-next-hover");
5762 .delegate( selector, "mouseover", datepicker_handleMouseover );
5765 function datepicker_handleMouseover() {
5766 if (!$.datepicker._isDisabledDatepicker( datepicker_instActive.inline? datepicker_instActive.dpDiv.parent()[0] : datepicker_instActive.input[0])) {
5767 $(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");
5768 $(this).addClass("ui-state-hover");
5769 if (this.className.indexOf("ui-datepicker-prev") !== -1) {
5770 $(this).addClass("ui-datepicker-prev-hover");
5772 if (this.className.indexOf("ui-datepicker-next") !== -1) {
5773 $(this).addClass("ui-datepicker-next-hover");
5778 /* jQuery extend now ignores nulls! */
5779 function datepicker_extendRemove(target, props) {
5780 $.extend(target, props);
5781 for (var name in props) {
5782 if (props[name] == null) {
5783 target[name] = props[name];
5789 /* Invoke the datepicker functionality.
5790 @param options string - a command, optionally followed by additional parameters or
5791 Object - settings for attaching new datepicker functionality
5792 @return jQuery object */
5793 $.fn.datepicker = function(options){
5795 /* Verify an empty collection wasn't passed - Fixes #6976 */
5796 if ( !this.length ) {
5800 /* Initialise the date picker. */
5801 if (!$.datepicker.initialized) {
5802 $(document).mousedown($.datepicker._checkExternalClick);
5803 $.datepicker.initialized = true;
5806 /* Append datepicker main container to body if not exist. */
5807 if ($("#"+$.datepicker._mainDivId).length === 0) {
5808 $("body").append($.datepicker.dpDiv);
5811 var otherArgs = Array.prototype.slice.call(arguments, 1);
5812 if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) {
5813 return $.datepicker["_" + options + "Datepicker"].
5814 apply($.datepicker, [this[0]].concat(otherArgs));
5816 if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") {
5817 return $.datepicker["_" + options + "Datepicker"].
5818 apply($.datepicker, [this[0]].concat(otherArgs));
5820 return this.each(function() {
5821 typeof options === "string" ?
5822 $.datepicker["_" + options + "Datepicker"].
5823 apply($.datepicker, [this].concat(otherArgs)) :
5824 $.datepicker._attachDatepicker(this, options);
5828 $.datepicker = new Datepicker(); // singleton instance
5829 $.datepicker.initialized = false;
5830 $.datepicker.uuid = new Date().getTime();
5831 $.datepicker.version = "1.11.3";
5833 var datepicker = $.datepicker;
5837 * jQuery UI Draggable 1.11.3
5838 * http://jqueryui.com
5840 * Copyright jQuery Foundation and other contributors
5841 * Released under the MIT license.
5842 * http://jquery.org/license
5844 * http://api.jqueryui.com/draggable/
5848 $.widget("ui.draggable", $.ui.mouse, {
5850 widgetEventPrefix: "drag",
5855 connectToSortable: false,
5864 refreshPositions: false,
5866 revertDuration: 500,
5869 scrollSensitivity: 20,
5882 _create: function() {
5884 if ( this.options.helper === "original" ) {
5885 this._setPositionRelative();
5887 if (this.options.addClasses){
5888 this.element.addClass("ui-draggable");
5890 if (this.options.disabled){
5891 this.element.addClass("ui-draggable-disabled");
5893 this._setHandleClassName();
5898 _setOption: function( key, value ) {
5899 this._super( key, value );
5900 if ( key === "handle" ) {
5901 this._removeHandleClassName();
5902 this._setHandleClassName();
5906 _destroy: function() {
5907 if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) {
5908 this.destroyOnClear = true;
5911 this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" );
5912 this._removeHandleClassName();
5913 this._mouseDestroy();
5916 _mouseCapture: function(event) {
5917 var o = this.options;
5919 this._blurActiveElement( event );
5921 // among others, prevent a drag on a resizable-handle
5922 if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) {
5926 //Quit if we're not on a valid handle
5927 this.handle = this._getHandle(event);
5932 this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix );
5938 _blockFrames: function( selector ) {
5939 this.iframeBlocks = this.document.find( selector ).map(function() {
5940 var iframe = $( this );
5943 .css( "position", "absolute" )
5944 .appendTo( iframe.parent() )
5945 .outerWidth( iframe.outerWidth() )
5946 .outerHeight( iframe.outerHeight() )
5947 .offset( iframe.offset() )[ 0 ];
5951 _unblockFrames: function() {
5952 if ( this.iframeBlocks ) {
5953 this.iframeBlocks.remove();
5954 delete this.iframeBlocks;
5958 _blurActiveElement: function( event ) {
5959 var document = this.document[ 0 ];
5961 // Only need to blur if the event occurred on the draggable itself, see #10527
5962 if ( !this.handleElement.is( event.target ) ) {
5967 // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
5970 // Support: IE9, IE10
5971 // If the <body> is blurred, IE will switch windows, see #9520
5972 if ( document.activeElement && document.activeElement.nodeName.toLowerCase() !== "body" ) {
5974 // Blur any element that currently has focus, see #4261
5975 $( document.activeElement ).blur();
5977 } catch ( error ) {}
5980 _mouseStart: function(event) {
5982 var o = this.options;
5984 //Create and append the visible helper
5985 this.helper = this._createHelper(event);
5987 this.helper.addClass("ui-draggable-dragging");
5989 //Cache the helper size
5990 this._cacheHelperProportions();
5992 //If ddmanager is used for droppables, set the global draggable
5993 if ($.ui.ddmanager) {
5994 $.ui.ddmanager.current = this;
5998 * - Position generation -
5999 * This block generates everything position related - it's the core of draggables.
6002 //Cache the margins of the original element
6003 this._cacheMargins();
6005 //Store the helper's css position
6006 this.cssPosition = this.helper.css( "position" );
6007 this.scrollParent = this.helper.scrollParent( true );
6008 this.offsetParent = this.helper.offsetParent();
6009 this.hasFixedAncestor = this.helper.parents().filter(function() {
6010 return $( this ).css( "position" ) === "fixed";
6013 //The element's absolute position on the page minus margins
6014 this.positionAbs = this.element.offset();
6015 this._refreshOffsets( event );
6017 //Generate the original position
6018 this.originalPosition = this.position = this._generatePosition( event, false );
6019 this.originalPageX = event.pageX;
6020 this.originalPageY = event.pageY;
6022 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
6023 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
6025 //Set a containment if given in the options
6026 this._setContainment();
6028 //Trigger event + callbacks
6029 if (this._trigger("start", event) === false) {
6034 //Recache the helper size
6035 this._cacheHelperProportions();
6037 //Prepare the droppable offsets
6038 if ($.ui.ddmanager && !o.dropBehaviour) {
6039 $.ui.ddmanager.prepareOffsets(this, event);
6042 // Reset helper's right/bottom css if they're set and set explicit width/height instead
6043 // as this prevents resizing of elements with right/bottom set (see #7772)
6044 this._normalizeRightBottom();
6046 this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
6048 //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
6049 if ( $.ui.ddmanager ) {
6050 $.ui.ddmanager.dragStart(this, event);
6056 _refreshOffsets: function( event ) {
6058 top: this.positionAbs.top - this.margins.top,
6059 left: this.positionAbs.left - this.margins.left,
6061 parent: this._getParentOffset(),
6062 relative: this._getRelativeOffset()
6065 this.offset.click = {
6066 left: event.pageX - this.offset.left,
6067 top: event.pageY - this.offset.top
6071 _mouseDrag: function(event, noPropagation) {
6072 // reset any necessary cached properties (see #5009)
6073 if ( this.hasFixedAncestor ) {
6074 this.offset.parent = this._getParentOffset();
6077 //Compute the helpers position
6078 this.position = this._generatePosition( event, true );
6079 this.positionAbs = this._convertPositionTo("absolute");
6081 //Call plugins and callbacks and use the resulting position if something is returned
6082 if (!noPropagation) {
6083 var ui = this._uiHash();
6084 if (this._trigger("drag", event, ui) === false) {
6088 this.position = ui.position;
6091 this.helper[ 0 ].style.left = this.position.left + "px";
6092 this.helper[ 0 ].style.top = this.position.top + "px";
6094 if ($.ui.ddmanager) {
6095 $.ui.ddmanager.drag(this, event);
6101 _mouseStop: function(event) {
6103 //If we are using droppables, inform the manager about the drop
6106 if ($.ui.ddmanager && !this.options.dropBehaviour) {
6107 dropped = $.ui.ddmanager.drop(this, event);
6110 //if a drop comes from outside (a sortable)
6112 dropped = this.dropped;
6113 this.dropped = false;
6116 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))) {
6117 $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
6118 if (that._trigger("stop", event) !== false) {
6123 if (this._trigger("stop", event) !== false) {
6131 _mouseUp: function( event ) {
6132 this._unblockFrames();
6134 //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003)
6135 if ( $.ui.ddmanager ) {
6136 $.ui.ddmanager.dragStop(this, event);
6139 // Only need to focus if the event occurred on the draggable itself, see #10527
6140 if ( this.handleElement.is( event.target ) ) {
6141 // The interaction is over; whether or not the click resulted in a drag, focus the element
6142 this.element.focus();
6145 return $.ui.mouse.prototype._mouseUp.call(this, event);
6148 cancel: function() {
6150 if (this.helper.is(".ui-draggable-dragging")) {
6160 _getHandle: function(event) {
6161 return this.options.handle ?
6162 !!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
6166 _setHandleClassName: function() {
6167 this.handleElement = this.options.handle ?
6168 this.element.find( this.options.handle ) : this.element;
6169 this.handleElement.addClass( "ui-draggable-handle" );
6172 _removeHandleClassName: function() {
6173 this.handleElement.removeClass( "ui-draggable-handle" );
6176 _createHelper: function(event) {
6178 var o = this.options,
6179 helperIsFunction = $.isFunction( o.helper ),
6180 helper = helperIsFunction ?
6181 $( o.helper.apply( this.element[ 0 ], [ event ] ) ) :
6182 ( o.helper === "clone" ?
6183 this.element.clone().removeAttr( "id" ) :
6186 if (!helper.parents("body").length) {
6187 helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo));
6190 // http://bugs.jqueryui.com/ticket/9446
6191 // a helper function can return the original element
6192 // which wouldn't have been set to relative in _create
6193 if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) {
6194 this._setPositionRelative();
6197 if (helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) {
6198 helper.css("position", "absolute");
6205 _setPositionRelative: function() {
6206 if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) {
6207 this.element[ 0 ].style.position = "relative";
6211 _adjustOffsetFromHelper: function(obj) {
6212 if (typeof obj === "string") {
6213 obj = obj.split(" ");
6215 if ($.isArray(obj)) {
6216 obj = { left: +obj[0], top: +obj[1] || 0 };
6218 if ("left" in obj) {
6219 this.offset.click.left = obj.left + this.margins.left;
6221 if ("right" in obj) {
6222 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
6225 this.offset.click.top = obj.top + this.margins.top;
6227 if ("bottom" in obj) {
6228 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
6232 _isRootNode: function( element ) {
6233 return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ];
6236 _getParentOffset: function() {
6238 //Get the offsetParent and cache its position
6239 var po = this.offsetParent.offset(),
6240 document = this.document[ 0 ];
6242 // This is a special case where we need to modify a offset calculated on start, since the following happened:
6243 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
6244 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
6245 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
6246 if (this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
6247 po.left += this.scrollParent.scrollLeft();
6248 po.top += this.scrollParent.scrollTop();
6251 if ( this._isRootNode( this.offsetParent[ 0 ] ) ) {
6252 po = { top: 0, left: 0 };
6256 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"), 10) || 0),
6257 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"), 10) || 0)
6262 _getRelativeOffset: function() {
6263 if ( this.cssPosition !== "relative" ) {
6264 return { top: 0, left: 0 };
6267 var p = this.element.position(),
6268 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
6271 top: p.top - ( parseInt(this.helper.css( "top" ), 10) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ),
6272 left: p.left - ( parseInt(this.helper.css( "left" ), 10) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 )
6277 _cacheMargins: function() {
6279 left: (parseInt(this.element.css("marginLeft"), 10) || 0),
6280 top: (parseInt(this.element.css("marginTop"), 10) || 0),
6281 right: (parseInt(this.element.css("marginRight"), 10) || 0),
6282 bottom: (parseInt(this.element.css("marginBottom"), 10) || 0)
6286 _cacheHelperProportions: function() {
6287 this.helperProportions = {
6288 width: this.helper.outerWidth(),
6289 height: this.helper.outerHeight()
6293 _setContainment: function() {
6295 var isUserScrollable, c, ce,
6297 document = this.document[ 0 ];
6299 this.relativeContainer = null;
6301 if ( !o.containment ) {
6302 this.containment = null;
6306 if ( o.containment === "window" ) {
6307 this.containment = [
6308 $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
6309 $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
6310 $( window ).scrollLeft() + $( window ).width() - this.helperProportions.width - this.margins.left,
6311 $( window ).scrollTop() + ( $( window ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
6316 if ( o.containment === "document") {
6317 this.containment = [
6320 $( document ).width() - this.helperProportions.width - this.margins.left,
6321 ( $( document ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
6326 if ( o.containment.constructor === Array ) {
6327 this.containment = o.containment;
6331 if ( o.containment === "parent" ) {
6332 o.containment = this.helper[ 0 ].parentNode;
6335 c = $( o.containment );
6342 isUserScrollable = /(scroll|auto)/.test( c.css( "overflow" ) );
6344 this.containment = [
6345 ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
6346 ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ),
6347 ( isUserScrollable ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
6348 ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) -
6349 ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) -
6350 this.helperProportions.width -
6353 ( isUserScrollable ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
6354 ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) -
6355 ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) -
6356 this.helperProportions.height -
6360 this.relativeContainer = c;
6363 _convertPositionTo: function(d, pos) {
6366 pos = this.position;
6369 var mod = d === "absolute" ? 1 : -1,
6370 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
6374 pos.top + // The absolute mouse position
6375 this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
6376 this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
6377 ( ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod)
6380 pos.left + // The absolute mouse position
6381 this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
6382 this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
6383 ( ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod)
6389 _generatePosition: function( event, constrainPosition ) {
6391 var containment, co, top, left,
6393 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ),
6394 pageX = event.pageX,
6395 pageY = event.pageY;
6398 if ( !scrollIsRootNode || !this.offset.scroll ) {
6399 this.offset.scroll = {
6400 top: this.scrollParent.scrollTop(),
6401 left: this.scrollParent.scrollLeft()
6406 * - Position constraining -
6407 * Constrain the position to a mix of grid, containment.
6410 // If we are not dragging yet, we won't check for options
6411 if ( constrainPosition ) {
6412 if ( this.containment ) {
6413 if ( this.relativeContainer ){
6414 co = this.relativeContainer.offset();
6416 this.containment[ 0 ] + co.left,
6417 this.containment[ 1 ] + co.top,
6418 this.containment[ 2 ] + co.left,
6419 this.containment[ 3 ] + co.top
6422 containment = this.containment;
6425 if (event.pageX - this.offset.click.left < containment[0]) {
6426 pageX = containment[0] + this.offset.click.left;
6428 if (event.pageY - this.offset.click.top < containment[1]) {
6429 pageY = containment[1] + this.offset.click.top;
6431 if (event.pageX - this.offset.click.left > containment[2]) {
6432 pageX = containment[2] + this.offset.click.left;
6434 if (event.pageY - this.offset.click.top > containment[3]) {
6435 pageY = containment[3] + this.offset.click.top;
6440 //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950)
6441 top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY;
6442 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;
6444 left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX;
6445 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;
6448 if ( o.axis === "y" ) {
6449 pageX = this.originalPageX;
6452 if ( o.axis === "x" ) {
6453 pageY = this.originalPageY;
6459 pageY - // The absolute mouse position
6460 this.offset.click.top - // Click offset (relative to the element)
6461 this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
6462 this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
6463 ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) )
6466 pageX - // The absolute mouse position
6467 this.offset.click.left - // Click offset (relative to the element)
6468 this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
6469 this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
6470 ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) )
6476 _clear: function() {
6477 this.helper.removeClass("ui-draggable-dragging");
6478 if (this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) {
6479 this.helper.remove();
6482 this.cancelHelperRemoval = false;
6483 if ( this.destroyOnClear ) {
6488 _normalizeRightBottom: function() {
6489 if ( this.options.axis !== "y" && this.helper.css( "right" ) !== "auto" ) {
6490 this.helper.width( this.helper.width() );
6491 this.helper.css( "right", "auto" );
6493 if ( this.options.axis !== "x" && this.helper.css( "bottom" ) !== "auto" ) {
6494 this.helper.height( this.helper.height() );
6495 this.helper.css( "bottom", "auto" );
6499 // From now on bulk stuff - mainly helpers
6501 _trigger: function( type, event, ui ) {
6502 ui = ui || this._uiHash();
6503 $.ui.plugin.call( this, type, [ event, ui, this ], true );
6505 // Absolute position and offset (see #6884 ) have to be recalculated after plugins
6506 if ( /^(drag|start|stop)/.test( type ) ) {
6507 this.positionAbs = this._convertPositionTo( "absolute" );
6508 ui.offset = this.positionAbs;
6510 return $.Widget.prototype._trigger.call( this, type, event, ui );
6515 _uiHash: function() {
6517 helper: this.helper,
6518 position: this.position,
6519 originalPosition: this.originalPosition,
6520 offset: this.positionAbs
6526 $.ui.plugin.add( "draggable", "connectToSortable", {
6527 start: function( event, ui, draggable ) {
6528 var uiSortable = $.extend( {}, ui, {
6529 item: draggable.element
6532 draggable.sortables = [];
6533 $( draggable.options.connectToSortable ).each(function() {
6534 var sortable = $( this ).sortable( "instance" );
6536 if ( sortable && !sortable.options.disabled ) {
6537 draggable.sortables.push( sortable );
6539 // refreshPositions is called at drag start to refresh the containerCache
6540 // which is used in drag. This ensures it's initialized and synchronized
6541 // with any changes that might have happened on the page since initialization.
6542 sortable.refreshPositions();
6543 sortable._trigger("activate", event, uiSortable);
6547 stop: function( event, ui, draggable ) {
6548 var uiSortable = $.extend( {}, ui, {
6549 item: draggable.element
6552 draggable.cancelHelperRemoval = false;
6554 $.each( draggable.sortables, function() {
6555 var sortable = this;
6557 if ( sortable.isOver ) {
6558 sortable.isOver = 0;
6560 // Allow this sortable to handle removing the helper
6561 draggable.cancelHelperRemoval = true;
6562 sortable.cancelHelperRemoval = false;
6564 // Use _storedCSS To restore properties in the sortable,
6565 // as this also handles revert (#9675) since the draggable
6566 // may have modified them in unexpected ways (#8809)
6567 sortable._storedCSS = {
6568 position: sortable.placeholder.css( "position" ),
6569 top: sortable.placeholder.css( "top" ),
6570 left: sortable.placeholder.css( "left" )
6573 sortable._mouseStop(event);
6575 // Once drag has ended, the sortable should return to using
6576 // its original helper, not the shared helper from draggable
6577 sortable.options.helper = sortable.options._helper;
6579 // Prevent this Sortable from removing the helper.
6580 // However, don't set the draggable to remove the helper
6581 // either as another connected Sortable may yet handle the removal.
6582 sortable.cancelHelperRemoval = true;
6584 sortable._trigger( "deactivate", event, uiSortable );
6588 drag: function( event, ui, draggable ) {
6589 $.each( draggable.sortables, function() {
6590 var innermostIntersecting = false,
6593 // Copy over variables that sortable's _intersectsWith uses
6594 sortable.positionAbs = draggable.positionAbs;
6595 sortable.helperProportions = draggable.helperProportions;
6596 sortable.offset.click = draggable.offset.click;
6598 if ( sortable._intersectsWith( sortable.containerCache ) ) {
6599 innermostIntersecting = true;
6601 $.each( draggable.sortables, function() {
6602 // Copy over variables that sortable's _intersectsWith uses
6603 this.positionAbs = draggable.positionAbs;
6604 this.helperProportions = draggable.helperProportions;
6605 this.offset.click = draggable.offset.click;
6607 if ( this !== sortable &&
6608 this._intersectsWith( this.containerCache ) &&
6609 $.contains( sortable.element[ 0 ], this.element[ 0 ] ) ) {
6610 innermostIntersecting = false;
6613 return innermostIntersecting;
6617 if ( innermostIntersecting ) {
6618 // If it intersects, we use a little isOver variable and set it once,
6619 // so that the move-in stuff gets fired only once.
6620 if ( !sortable.isOver ) {
6621 sortable.isOver = 1;
6623 sortable.currentItem = ui.helper
6624 .appendTo( sortable.element )
6625 .data( "ui-sortable-item", true );
6627 // Store helper option to later restore it
6628 sortable.options._helper = sortable.options.helper;
6630 sortable.options.helper = function() {
6631 return ui.helper[ 0 ];
6634 // Fire the start events of the sortable with our passed browser event,
6635 // and our own helper (so it doesn't create a new one)
6636 event.target = sortable.currentItem[ 0 ];
6637 sortable._mouseCapture( event, true );
6638 sortable._mouseStart( event, true, true );
6640 // Because the browser event is way off the new appended portlet,
6641 // modify necessary variables to reflect the changes
6642 sortable.offset.click.top = draggable.offset.click.top;
6643 sortable.offset.click.left = draggable.offset.click.left;
6644 sortable.offset.parent.left -= draggable.offset.parent.left -
6645 sortable.offset.parent.left;
6646 sortable.offset.parent.top -= draggable.offset.parent.top -
6647 sortable.offset.parent.top;
6649 draggable._trigger( "toSortable", event );
6651 // Inform draggable that the helper is in a valid drop zone,
6652 // used solely in the revert option to handle "valid/invalid".
6653 draggable.dropped = sortable.element;
6655 // Need to refreshPositions of all sortables in the case that
6656 // adding to one sortable changes the location of the other sortables (#9675)
6657 $.each( draggable.sortables, function() {
6658 this.refreshPositions();
6661 // hack so receive/update callbacks work (mostly)
6662 draggable.currentItem = draggable.element;
6663 sortable.fromOutside = draggable;
6666 if ( sortable.currentItem ) {
6667 sortable._mouseDrag( event );
6668 // Copy the sortable's position because the draggable's can potentially reflect
6669 // a relative position, while sortable is always absolute, which the dragged
6670 // element has now become. (#8809)
6671 ui.position = sortable.position;
6674 // If it doesn't intersect with the sortable, and it intersected before,
6675 // we fake the drag stop of the sortable, but make sure it doesn't remove
6676 // the helper by using cancelHelperRemoval.
6677 if ( sortable.isOver ) {
6679 sortable.isOver = 0;
6680 sortable.cancelHelperRemoval = true;
6682 // Calling sortable's mouseStop would trigger a revert,
6683 // so revert must be temporarily false until after mouseStop is called.
6684 sortable.options._revert = sortable.options.revert;
6685 sortable.options.revert = false;
6687 sortable._trigger( "out", event, sortable._uiHash( sortable ) );
6688 sortable._mouseStop( event, true );
6690 // restore sortable behaviors that were modfied
6691 // when the draggable entered the sortable area (#9481)
6692 sortable.options.revert = sortable.options._revert;
6693 sortable.options.helper = sortable.options._helper;
6695 if ( sortable.placeholder ) {
6696 sortable.placeholder.remove();
6699 // Recalculate the draggable's offset considering the sortable
6700 // may have modified them in unexpected ways (#8809)
6701 draggable._refreshOffsets( event );
6702 ui.position = draggable._generatePosition( event, true );
6704 draggable._trigger( "fromSortable", event );
6706 // Inform draggable that the helper is no longer in a valid drop zone
6707 draggable.dropped = false;
6709 // Need to refreshPositions of all sortables just in case removing
6710 // from one sortable changes the location of other sortables (#9675)
6711 $.each( draggable.sortables, function() {
6712 this.refreshPositions();
6720 $.ui.plugin.add("draggable", "cursor", {
6721 start: function( event, ui, instance ) {
6722 var t = $( "body" ),
6723 o = instance.options;
6725 if (t.css("cursor")) {
6726 o._cursor = t.css("cursor");
6728 t.css("cursor", o.cursor);
6730 stop: function( event, ui, instance ) {
6731 var o = instance.options;
6733 $("body").css("cursor", o._cursor);
6738 $.ui.plugin.add("draggable", "opacity", {
6739 start: function( event, ui, instance ) {
6740 var t = $( ui.helper ),
6741 o = instance.options;
6742 if (t.css("opacity")) {
6743 o._opacity = t.css("opacity");
6745 t.css("opacity", o.opacity);
6747 stop: function( event, ui, instance ) {
6748 var o = instance.options;
6750 $(ui.helper).css("opacity", o._opacity);
6755 $.ui.plugin.add("draggable", "scroll", {
6756 start: function( event, ui, i ) {
6757 if ( !i.scrollParentNotHidden ) {
6758 i.scrollParentNotHidden = i.helper.scrollParent( false );
6761 if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] && i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) {
6762 i.overflowOffset = i.scrollParentNotHidden.offset();
6765 drag: function( event, ui, i ) {
6769 scrollParent = i.scrollParentNotHidden[ 0 ],
6770 document = i.document[ 0 ];
6772 if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) {
6773 if ( !o.axis || o.axis !== "x" ) {
6774 if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY < o.scrollSensitivity ) {
6775 scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed;
6776 } else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) {
6777 scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed;
6781 if ( !o.axis || o.axis !== "y" ) {
6782 if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX < o.scrollSensitivity ) {
6783 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed;
6784 } else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) {
6785 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed;
6791 if (!o.axis || o.axis !== "x") {
6792 if (event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
6793 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
6794 } else if ($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
6795 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
6799 if (!o.axis || o.axis !== "y") {
6800 if (event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
6801 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
6802 } else if ($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
6803 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
6809 if (scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
6810 $.ui.ddmanager.prepareOffsets(i, event);
6816 $.ui.plugin.add("draggable", "snap", {
6817 start: function( event, ui, i ) {
6821 i.snapElements = [];
6823 $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() {
6826 if (this !== i.element[0]) {
6827 i.snapElements.push({
6829 width: $t.outerWidth(), height: $t.outerHeight(),
6830 top: $o.top, left: $o.left
6836 drag: function( event, ui, inst ) {
6838 var ts, bs, ls, rs, l, r, t, b, i, first,
6840 d = o.snapTolerance,
6841 x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
6842 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
6844 for (i = inst.snapElements.length - 1; i >= 0; i--){
6846 l = inst.snapElements[i].left - inst.margins.left;
6847 r = l + inst.snapElements[i].width;
6848 t = inst.snapElements[i].top - inst.margins.top;
6849 b = t + inst.snapElements[i].height;
6851 if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || !$.contains( inst.snapElements[ i ].item.ownerDocument, inst.snapElements[ i ].item ) ) {
6852 if (inst.snapElements[i].snapping) {
6853 (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
6855 inst.snapElements[i].snapping = false;
6859 if (o.snapMode !== "inner") {
6860 ts = Math.abs(t - y2) <= d;
6861 bs = Math.abs(b - y1) <= d;
6862 ls = Math.abs(l - x2) <= d;
6863 rs = Math.abs(r - x1) <= d;
6865 ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top;
6868 ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top;
6871 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left;
6874 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left;
6878 first = (ts || bs || ls || rs);
6880 if (o.snapMode !== "outer") {
6881 ts = Math.abs(t - y1) <= d;
6882 bs = Math.abs(b - y2) <= d;
6883 ls = Math.abs(l - x1) <= d;
6884 rs = Math.abs(r - x2) <= d;
6886 ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top;
6889 ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top;
6892 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left;
6895 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left;
6899 if (!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) {
6900 (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
6902 inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
6909 $.ui.plugin.add("draggable", "stack", {
6910 start: function( event, ui, instance ) {
6912 o = instance.options,
6913 group = $.makeArray($(o.stack)).sort(function(a, b) {
6914 return (parseInt($(a).css("zIndex"), 10) || 0) - (parseInt($(b).css("zIndex"), 10) || 0);
6917 if (!group.length) { return; }
6919 min = parseInt($(group[0]).css("zIndex"), 10) || 0;
6920 $(group).each(function(i) {
6921 $(this).css("zIndex", min + i);
6923 this.css("zIndex", (min + group.length));
6927 $.ui.plugin.add("draggable", "zIndex", {
6928 start: function( event, ui, instance ) {
6929 var t = $( ui.helper ),
6930 o = instance.options;
6932 if (t.css("zIndex")) {
6933 o._zIndex = t.css("zIndex");
6935 t.css("zIndex", o.zIndex);
6937 stop: function( event, ui, instance ) {
6938 var o = instance.options;
6941 $(ui.helper).css("zIndex", o._zIndex);
6946 var draggable = $.ui.draggable;
6950 * jQuery UI Resizable 1.11.3
6951 * http://jqueryui.com
6953 * Copyright jQuery Foundation and other contributors
6954 * Released under the MIT license.
6955 * http://jquery.org/license
6957 * http://api.jqueryui.com/resizable/
6961 $.widget("ui.resizable", $.ui.mouse, {
6963 widgetEventPrefix: "resize",
6967 animateDuration: "slow",
6968 animateEasing: "swing",
6989 _num: function( value ) {
6990 return parseInt( value, 10 ) || 0;
6993 _isNumber: function( value ) {
6994 return !isNaN( parseInt( value, 10 ) );
6997 _hasScroll: function( el, a ) {
6999 if ( $( el ).css( "overflow" ) === "hidden") {
7003 var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
7006 if ( el[ scroll ] > 0 ) {
7010 // TODO: determine which cases actually cause this to happen
7011 // if the element doesn't have the scroll set, see if it's possible to
7014 has = ( el[ scroll ] > 0 );
7019 _create: function() {
7021 var n, i, handle, axis, hname,
7024 this.element.addClass("ui-resizable");
7027 _aspectRatio: !!(o.aspectRatio),
7028 aspectRatio: o.aspectRatio,
7029 originalElement: this.element,
7030 _proportionallyResizeElements: [],
7031 _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
7034 // Wrap the element if it cannot hold child nodes
7035 if (this.element[0].nodeName.match(/^(canvas|textarea|input|select|button|img)$/i)) {
7038 $("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({
7039 position: this.element.css("position"),
7040 width: this.element.outerWidth(),
7041 height: this.element.outerHeight(),
7042 top: this.element.css("top"),
7043 left: this.element.css("left")
7047 this.element = this.element.parent().data(
7048 "ui-resizable", this.element.resizable( "instance" )
7051 this.elementIsWrapper = true;
7054 marginLeft: this.originalElement.css("marginLeft"),
7055 marginTop: this.originalElement.css("marginTop"),
7056 marginRight: this.originalElement.css("marginRight"),
7057 marginBottom: this.originalElement.css("marginBottom")
7059 this.originalElement.css({
7066 // Prevent Safari textarea resize
7067 this.originalResizeStyle = this.originalElement.css("resize");
7068 this.originalElement.css("resize", "none");
7070 this._proportionallyResizeElements.push( this.originalElement.css({
7077 // avoid IE jump (hard set the margin)
7078 this.originalElement.css({ margin: this.originalElement.css("margin") });
7080 this._proportionallyResize();
7083 this.handles = o.handles ||
7084 ( !$(".ui-resizable-handle", this.element).length ?
7086 n: ".ui-resizable-n",
7087 e: ".ui-resizable-e",
7088 s: ".ui-resizable-s",
7089 w: ".ui-resizable-w",
7090 se: ".ui-resizable-se",
7091 sw: ".ui-resizable-sw",
7092 ne: ".ui-resizable-ne",
7093 nw: ".ui-resizable-nw"
7096 if (this.handles.constructor === String) {
7098 if ( this.handles === "all") {
7099 this.handles = "n,e,s,w,se,sw,ne,nw";
7102 n = this.handles.split(",");
7105 for (i = 0; i < n.length; i++) {
7107 handle = $.trim(n[i]);
7108 hname = "ui-resizable-" + handle;
7109 axis = $("<div class='ui-resizable-handle " + hname + "'></div>");
7111 axis.css({ zIndex: o.zIndex });
7113 // TODO : What's going on here?
7114 if ("se" === handle) {
7115 axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se");
7118 this.handles[handle] = ".ui-resizable-" + handle;
7119 this.element.append(axis);
7124 this._renderAxis = function(target) {
7126 var i, axis, padPos, padWrapper;
7128 target = target || this.element;
7130 for (i in this.handles) {
7132 if (this.handles[i].constructor === String) {
7133 this.handles[i] = this.element.children( this.handles[ i ] ).first().show();
7136 if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)) {
7138 axis = $(this.handles[i], this.element);
7140 padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
7142 padPos = [ "padding",
7143 /ne|nw|n/.test(i) ? "Top" :
7144 /se|sw|s/.test(i) ? "Bottom" :
7145 /^e$/.test(i) ? "Right" : "Left" ].join("");
7147 target.css(padPos, padWrapper);
7149 this._proportionallyResize();
7153 // TODO: What's that good for? There's not anything to be executed left
7154 if (!$(this.handles[i]).length) {
7160 // TODO: make renderAxis a prototype function
7161 this._renderAxis(this.element);
7163 this._handles = $(".ui-resizable-handle", this.element)
7164 .disableSelection();
7166 this._handles.mouseover(function() {
7167 if (!that.resizing) {
7168 if (this.className) {
7169 axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
7171 that.axis = axis && axis[1] ? axis[1] : "se";
7176 this._handles.hide();
7178 .addClass("ui-resizable-autohide")
7179 .mouseenter(function() {
7183 $(this).removeClass("ui-resizable-autohide");
7184 that._handles.show();
7186 .mouseleave(function() {
7190 if (!that.resizing) {
7191 $(this).addClass("ui-resizable-autohide");
7192 that._handles.hide();
7201 _destroy: function() {
7203 this._mouseDestroy();
7206 _destroy = function(exp) {
7208 .removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing")
7209 .removeData("resizable")
7210 .removeData("ui-resizable")
7211 .unbind(".resizable")
7212 .find(".ui-resizable-handle")
7216 // TODO: Unwrap at same DOM position
7217 if (this.elementIsWrapper) {
7218 _destroy(this.element);
7219 wrapper = this.element;
7220 this.originalElement.css({
7221 position: wrapper.css("position"),
7222 width: wrapper.outerWidth(),
7223 height: wrapper.outerHeight(),
7224 top: wrapper.css("top"),
7225 left: wrapper.css("left")
7226 }).insertAfter( wrapper );
7230 this.originalElement.css("resize", this.originalResizeStyle);
7231 _destroy(this.originalElement);
7236 _mouseCapture: function(event) {
7240 for (i in this.handles) {
7241 handle = $(this.handles[i])[0];
7242 if (handle === event.target || $.contains(handle, event.target)) {
7247 return !this.options.disabled && capture;
7250 _mouseStart: function(event) {
7252 var curleft, curtop, cursor,
7256 this.resizing = true;
7258 this._renderProxy();
7260 curleft = this._num(this.helper.css("left"));
7261 curtop = this._num(this.helper.css("top"));
7263 if (o.containment) {
7264 curleft += $(o.containment).scrollLeft() || 0;
7265 curtop += $(o.containment).scrollTop() || 0;
7268 this.offset = this.helper.offset();
7269 this.position = { left: curleft, top: curtop };
7271 this.size = this._helper ? {
7272 width: this.helper.width(),
7273 height: this.helper.height()
7279 this.originalSize = this._helper ? {
7280 width: el.outerWidth(),
7281 height: el.outerHeight()
7288 width: el.outerWidth() - el.width(),
7289 height: el.outerHeight() - el.height()
7292 this.originalPosition = { left: curleft, top: curtop };
7293 this.originalMousePosition = { left: event.pageX, top: event.pageY };
7295 this.aspectRatio = (typeof o.aspectRatio === "number") ?
7297 ((this.originalSize.width / this.originalSize.height) || 1);
7299 cursor = $(".ui-resizable-" + this.axis).css("cursor");
7300 $("body").css("cursor", cursor === "auto" ? this.axis + "-resize" : cursor);
7302 el.addClass("ui-resizable-resizing");
7303 this._propagate("start", event);
7307 _mouseDrag: function(event) {
7310 smp = this.originalMousePosition,
7312 dx = (event.pageX - smp.left) || 0,
7313 dy = (event.pageY - smp.top) || 0,
7314 trigger = this._change[a];
7316 this._updatePrevProperties();
7322 data = trigger.apply(this, [ event, dx, dy ]);
7324 this._updateVirtualBoundaries(event.shiftKey);
7325 if (this._aspectRatio || event.shiftKey) {
7326 data = this._updateRatio(data, event);
7329 data = this._respectSize(data, event);
7331 this._updateCache(data);
7333 this._propagate("resize", event);
7335 props = this._applyChanges();
7337 if ( !this._helper && this._proportionallyResizeElements.length ) {
7338 this._proportionallyResize();
7341 if ( !$.isEmptyObject( props ) ) {
7342 this._updatePrevProperties();
7343 this._trigger( "resize", event, this.ui() );
7344 this._applyChanges();
7350 _mouseStop: function(event) {
7352 this.resizing = false;
7353 var pr, ista, soffseth, soffsetw, s, left, top,
7354 o = this.options, that = this;
7358 pr = this._proportionallyResizeElements;
7359 ista = pr.length && (/textarea/i).test(pr[0].nodeName);
7360 soffseth = ista && this._hasScroll(pr[0], "left") ? 0 : that.sizeDiff.height;
7361 soffsetw = ista ? 0 : that.sizeDiff.width;
7364 width: (that.helper.width() - soffsetw),
7365 height: (that.helper.height() - soffseth)
7367 left = (parseInt(that.element.css("left"), 10) +
7368 (that.position.left - that.originalPosition.left)) || null;
7369 top = (parseInt(that.element.css("top"), 10) +
7370 (that.position.top - that.originalPosition.top)) || null;
7373 this.element.css($.extend(s, { top: top, left: left }));
7376 that.helper.height(that.size.height);
7377 that.helper.width(that.size.width);
7379 if (this._helper && !o.animate) {
7380 this._proportionallyResize();
7384 $("body").css("cursor", "auto");
7386 this.element.removeClass("ui-resizable-resizing");
7388 this._propagate("stop", event);
7391 this.helper.remove();
7398 _updatePrevProperties: function() {
7399 this.prevPosition = {
7400 top: this.position.top,
7401 left: this.position.left
7404 width: this.size.width,
7405 height: this.size.height
7409 _applyChanges: function() {
7412 if ( this.position.top !== this.prevPosition.top ) {
7413 props.top = this.position.top + "px";
7415 if ( this.position.left !== this.prevPosition.left ) {
7416 props.left = this.position.left + "px";
7418 if ( this.size.width !== this.prevSize.width ) {
7419 props.width = this.size.width + "px";
7421 if ( this.size.height !== this.prevSize.height ) {
7422 props.height = this.size.height + "px";
7425 this.helper.css( props );
7430 _updateVirtualBoundaries: function(forceAspectRatio) {
7431 var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
7435 minWidth: this._isNumber(o.minWidth) ? o.minWidth : 0,
7436 maxWidth: this._isNumber(o.maxWidth) ? o.maxWidth : Infinity,
7437 minHeight: this._isNumber(o.minHeight) ? o.minHeight : 0,
7438 maxHeight: this._isNumber(o.maxHeight) ? o.maxHeight : Infinity
7441 if (this._aspectRatio || forceAspectRatio) {
7442 pMinWidth = b.minHeight * this.aspectRatio;
7443 pMinHeight = b.minWidth / this.aspectRatio;
7444 pMaxWidth = b.maxHeight * this.aspectRatio;
7445 pMaxHeight = b.maxWidth / this.aspectRatio;
7447 if (pMinWidth > b.minWidth) {
7448 b.minWidth = pMinWidth;
7450 if (pMinHeight > b.minHeight) {
7451 b.minHeight = pMinHeight;
7453 if (pMaxWidth < b.maxWidth) {
7454 b.maxWidth = pMaxWidth;
7456 if (pMaxHeight < b.maxHeight) {
7457 b.maxHeight = pMaxHeight;
7460 this._vBoundaries = b;
7463 _updateCache: function(data) {
7464 this.offset = this.helper.offset();
7465 if (this._isNumber(data.left)) {
7466 this.position.left = data.left;
7468 if (this._isNumber(data.top)) {
7469 this.position.top = data.top;
7471 if (this._isNumber(data.height)) {
7472 this.size.height = data.height;
7474 if (this._isNumber(data.width)) {
7475 this.size.width = data.width;
7479 _updateRatio: function( data ) {
7481 var cpos = this.position,
7485 if (this._isNumber(data.height)) {
7486 data.width = (data.height * this.aspectRatio);
7487 } else if (this._isNumber(data.width)) {
7488 data.height = (data.width / this.aspectRatio);
7492 data.left = cpos.left + (csize.width - data.width);
7496 data.top = cpos.top + (csize.height - data.height);
7497 data.left = cpos.left + (csize.width - data.width);
7503 _respectSize: function( data ) {
7505 var o = this._vBoundaries,
7507 ismaxw = this._isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width),
7508 ismaxh = this._isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height),
7509 isminw = this._isNumber(data.width) && o.minWidth && (o.minWidth > data.width),
7510 isminh = this._isNumber(data.height) && o.minHeight && (o.minHeight > data.height),
7511 dw = this.originalPosition.left + this.originalSize.width,
7512 dh = this.position.top + this.size.height,
7513 cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
7515 data.width = o.minWidth;
7518 data.height = o.minHeight;
7521 data.width = o.maxWidth;
7524 data.height = o.maxHeight;
7528 data.left = dw - o.minWidth;
7531 data.left = dw - o.maxWidth;
7534 data.top = dh - o.minHeight;
7537 data.top = dh - o.maxHeight;
7540 // Fixing jump error on top/left - bug #2330
7541 if (!data.width && !data.height && !data.left && data.top) {
7543 } else if (!data.width && !data.height && !data.top && data.left) {
7550 _getPaddingPlusBorderDimensions: function( element ) {
7554 element.css( "borderTopWidth" ),
7555 element.css( "borderRightWidth" ),
7556 element.css( "borderBottomWidth" ),
7557 element.css( "borderLeftWidth" )
7560 element.css( "paddingTop" ),
7561 element.css( "paddingRight" ),
7562 element.css( "paddingBottom" ),
7563 element.css( "paddingLeft" )
7566 for ( ; i < 4; i++ ) {
7567 widths[ i ] = ( parseInt( borders[ i ], 10 ) || 0 );
7568 widths[ i ] += ( parseInt( paddings[ i ], 10 ) || 0 );
7572 height: widths[ 0 ] + widths[ 2 ],
7573 width: widths[ 1 ] + widths[ 3 ]
7577 _proportionallyResize: function() {
7579 if (!this._proportionallyResizeElements.length) {
7585 element = this.helper || this.element;
7587 for ( ; i < this._proportionallyResizeElements.length; i++) {
7589 prel = this._proportionallyResizeElements[i];
7591 // TODO: Seems like a bug to cache this.outerDimensions
7592 // considering that we are in a loop.
7593 if (!this.outerDimensions) {
7594 this.outerDimensions = this._getPaddingPlusBorderDimensions( prel );
7598 height: (element.height() - this.outerDimensions.height) || 0,
7599 width: (element.width() - this.outerDimensions.width) || 0
7606 _renderProxy: function() {
7608 var el = this.element, o = this.options;
7609 this.elementOffset = el.offset();
7613 this.helper = this.helper || $("<div style='overflow:hidden;'></div>");
7615 this.helper.addClass(this._helper).css({
7616 width: this.element.outerWidth() - 1,
7617 height: this.element.outerHeight() - 1,
7618 position: "absolute",
7619 left: this.elementOffset.left + "px",
7620 top: this.elementOffset.top + "px",
7621 zIndex: ++o.zIndex //TODO: Don't modify option
7626 .disableSelection();
7629 this.helper = this.element;
7635 e: function(event, dx) {
7636 return { width: this.originalSize.width + dx };
7638 w: function(event, dx) {
7639 var cs = this.originalSize, sp = this.originalPosition;
7640 return { left: sp.left + dx, width: cs.width - dx };
7642 n: function(event, dx, dy) {
7643 var cs = this.originalSize, sp = this.originalPosition;
7644 return { top: sp.top + dy, height: cs.height - dy };
7646 s: function(event, dx, dy) {
7647 return { height: this.originalSize.height + dy };
7649 se: function(event, dx, dy) {
7650 return $.extend(this._change.s.apply(this, arguments),
7651 this._change.e.apply(this, [ event, dx, dy ]));
7653 sw: function(event, dx, dy) {
7654 return $.extend(this._change.s.apply(this, arguments),
7655 this._change.w.apply(this, [ event, dx, dy ]));
7657 ne: function(event, dx, dy) {
7658 return $.extend(this._change.n.apply(this, arguments),
7659 this._change.e.apply(this, [ event, dx, dy ]));
7661 nw: function(event, dx, dy) {
7662 return $.extend(this._change.n.apply(this, arguments),
7663 this._change.w.apply(this, [ event, dx, dy ]));
7667 _propagate: function(n, event) {
7668 $.ui.plugin.call(this, n, [ event, this.ui() ]);
7669 (n !== "resize" && this._trigger(n, event, this.ui()));
7676 originalElement: this.originalElement,
7677 element: this.element,
7678 helper: this.helper,
7679 position: this.position,
7681 originalSize: this.originalSize,
7682 originalPosition: this.originalPosition
7689 * Resizable Extensions
7692 $.ui.plugin.add("resizable", "animate", {
7694 stop: function( event ) {
7695 var that = $(this).resizable( "instance" ),
7697 pr = that._proportionallyResizeElements,
7698 ista = pr.length && (/textarea/i).test(pr[0].nodeName),
7699 soffseth = ista && that._hasScroll(pr[0], "left") ? 0 : that.sizeDiff.height,
7700 soffsetw = ista ? 0 : that.sizeDiff.width,
7701 style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) },
7702 left = (parseInt(that.element.css("left"), 10) +
7703 (that.position.left - that.originalPosition.left)) || null,
7704 top = (parseInt(that.element.css("top"), 10) +
7705 (that.position.top - that.originalPosition.top)) || null;
7707 that.element.animate(
7708 $.extend(style, top && left ? { top: top, left: left } : {}), {
7709 duration: o.animateDuration,
7710 easing: o.animateEasing,
7714 width: parseInt(that.element.css("width"), 10),
7715 height: parseInt(that.element.css("height"), 10),
7716 top: parseInt(that.element.css("top"), 10),
7717 left: parseInt(that.element.css("left"), 10)
7720 if (pr && pr.length) {
7721 $(pr[0]).css({ width: data.width, height: data.height });
7724 // propagating resize, and updating values for each animation step
7725 that._updateCache(data);
7726 that._propagate("resize", event);
7735 $.ui.plugin.add( "resizable", "containment", {
7738 var element, p, co, ch, cw, width, height,
7739 that = $( this ).resizable( "instance" ),
7743 ce = ( oc instanceof $ ) ? oc.get( 0 ) : ( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc;
7749 that.containerElement = $( ce );
7751 if ( /document/.test( oc ) || oc === document ) {
7752 that.containerOffset = {
7756 that.containerPosition = {
7762 element: $( document ),
7765 width: $( document ).width(),
7766 height: $( document ).height() || document.body.parentNode.scrollHeight
7771 $([ "Top", "Right", "Left", "Bottom" ]).each(function( i, name ) {
7772 p[ i ] = that._num( element.css( "padding" + name ) );
7775 that.containerOffset = element.offset();
7776 that.containerPosition = element.position();
7777 that.containerSize = {
7778 height: ( element.innerHeight() - p[ 3 ] ),
7779 width: ( element.innerWidth() - p[ 1 ] )
7782 co = that.containerOffset;
7783 ch = that.containerSize.height;
7784 cw = that.containerSize.width;
7785 width = ( that._hasScroll ( ce, "left" ) ? ce.scrollWidth : cw );
7786 height = ( that._hasScroll ( ce ) ? ce.scrollHeight : ch ) ;
7798 resize: function( event ) {
7799 var woset, hoset, isParent, isOffsetRelative,
7800 that = $( this ).resizable( "instance" ),
7802 co = that.containerOffset,
7804 pRatio = that._aspectRatio || event.shiftKey,
7809 ce = that.containerElement,
7810 continueResize = true;
7812 if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) {
7816 if ( cp.left < ( that._helper ? co.left : 0 ) ) {
7817 that.size.width = that.size.width +
7819 ( that.position.left - co.left ) :
7820 ( that.position.left - cop.left ) );
7823 that.size.height = that.size.width / that.aspectRatio;
7824 continueResize = false;
7826 that.position.left = o.helper ? co.left : 0;
7829 if ( cp.top < ( that._helper ? co.top : 0 ) ) {
7830 that.size.height = that.size.height +
7832 ( that.position.top - co.top ) :
7833 that.position.top );
7836 that.size.width = that.size.height * that.aspectRatio;
7837 continueResize = false;
7839 that.position.top = that._helper ? co.top : 0;
7842 isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 );
7843 isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) );
7845 if ( isParent && isOffsetRelative ) {
7846 that.offset.left = that.parentData.left + that.position.left;
7847 that.offset.top = that.parentData.top + that.position.top;
7849 that.offset.left = that.element.offset().left;
7850 that.offset.top = that.element.offset().top;
7853 woset = Math.abs( that.sizeDiff.width +
7855 that.offset.left - cop.left :
7856 (that.offset.left - co.left)) );
7858 hoset = Math.abs( that.sizeDiff.height +
7860 that.offset.top - cop.top :
7861 (that.offset.top - co.top)) );
7863 if ( woset + that.size.width >= that.parentData.width ) {
7864 that.size.width = that.parentData.width - woset;
7866 that.size.height = that.size.width / that.aspectRatio;
7867 continueResize = false;
7871 if ( hoset + that.size.height >= that.parentData.height ) {
7872 that.size.height = that.parentData.height - hoset;
7874 that.size.width = that.size.height * that.aspectRatio;
7875 continueResize = false;
7879 if ( !continueResize ) {
7880 that.position.left = that.prevPosition.left;
7881 that.position.top = that.prevPosition.top;
7882 that.size.width = that.prevSize.width;
7883 that.size.height = that.prevSize.height;
7888 var that = $( this ).resizable( "instance" ),
7890 co = that.containerOffset,
7891 cop = that.containerPosition,
7892 ce = that.containerElement,
7893 helper = $( that.helper ),
7894 ho = helper.offset(),
7895 w = helper.outerWidth() - that.sizeDiff.width,
7896 h = helper.outerHeight() - that.sizeDiff.height;
7898 if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) {
7900 left: ho.left - cop.left - co.left,
7906 if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) {
7908 left: ho.left - cop.left - co.left,
7916 $.ui.plugin.add("resizable", "alsoResize", {
7919 var that = $(this).resizable( "instance" ),
7921 _store = function(exp) {
7922 $(exp).each(function() {
7924 el.data("ui-resizable-alsoresize", {
7925 width: parseInt(el.width(), 10), height: parseInt(el.height(), 10),
7926 left: parseInt(el.css("left"), 10), top: parseInt(el.css("top"), 10)
7931 if (typeof(o.alsoResize) === "object" && !o.alsoResize.parentNode) {
7932 if (o.alsoResize.length) {
7933 o.alsoResize = o.alsoResize[0];
7934 _store(o.alsoResize);
7936 $.each(o.alsoResize, function(exp) {
7941 _store(o.alsoResize);
7945 resize: function(event, ui) {
7946 var that = $(this).resizable( "instance" ),
7948 os = that.originalSize,
7949 op = that.originalPosition,
7951 height: (that.size.height - os.height) || 0,
7952 width: (that.size.width - os.width) || 0,
7953 top: (that.position.top - op.top) || 0,
7954 left: (that.position.left - op.left) || 0
7957 _alsoResize = function(exp, c) {
7958 $(exp).each(function() {
7959 var el = $(this), start = $(this).data("ui-resizable-alsoresize"), style = {},
7960 css = c && c.length ?
7962 el.parents(ui.originalElement[0]).length ?
7963 [ "width", "height" ] :
7964 [ "width", "height", "top", "left" ];
7966 $.each(css, function(i, prop) {
7967 var sum = (start[prop] || 0) + (delta[prop] || 0);
7968 if (sum && sum >= 0) {
7969 style[prop] = sum || null;
7977 if (typeof(o.alsoResize) === "object" && !o.alsoResize.nodeType) {
7978 $.each(o.alsoResize, function(exp, c) {
7979 _alsoResize(exp, c);
7982 _alsoResize(o.alsoResize);
7987 $(this).removeData("resizable-alsoresize");
7991 $.ui.plugin.add("resizable", "ghost", {
7995 var that = $(this).resizable( "instance" ), o = that.options, cs = that.size;
7997 that.ghost = that.originalElement.clone();
8002 position: "relative",
8009 .addClass("ui-resizable-ghost")
8010 .addClass(typeof o.ghost === "string" ? o.ghost : "");
8012 that.ghost.appendTo(that.helper);
8016 resize: function() {
8017 var that = $(this).resizable( "instance" );
8020 position: "relative",
8021 height: that.size.height,
8022 width: that.size.width
8028 var that = $(this).resizable( "instance" );
8029 if (that.ghost && that.helper) {
8030 that.helper.get(0).removeChild(that.ghost.get(0));
8036 $.ui.plugin.add("resizable", "grid", {
8038 resize: function() {
8039 var outerDimensions,
8040 that = $(this).resizable( "instance" ),
8043 os = that.originalSize,
8044 op = that.originalPosition,
8046 grid = typeof o.grid === "number" ? [ o.grid, o.grid ] : o.grid,
8047 gridX = (grid[0] || 1),
8048 gridY = (grid[1] || 1),
8049 ox = Math.round((cs.width - os.width) / gridX) * gridX,
8050 oy = Math.round((cs.height - os.height) / gridY) * gridY,
8051 newWidth = os.width + ox,
8052 newHeight = os.height + oy,
8053 isMaxWidth = o.maxWidth && (o.maxWidth < newWidth),
8054 isMaxHeight = o.maxHeight && (o.maxHeight < newHeight),
8055 isMinWidth = o.minWidth && (o.minWidth > newWidth),
8056 isMinHeight = o.minHeight && (o.minHeight > newHeight);
8073 if (/^(se|s|e)$/.test(a)) {
8074 that.size.width = newWidth;
8075 that.size.height = newHeight;
8076 } else if (/^(ne)$/.test(a)) {
8077 that.size.width = newWidth;
8078 that.size.height = newHeight;
8079 that.position.top = op.top - oy;
8080 } else if (/^(sw)$/.test(a)) {
8081 that.size.width = newWidth;
8082 that.size.height = newHeight;
8083 that.position.left = op.left - ox;
8085 if ( newHeight - gridY <= 0 || newWidth - gridX <= 0) {
8086 outerDimensions = that._getPaddingPlusBorderDimensions( this );
8089 if ( newHeight - gridY > 0 ) {
8090 that.size.height = newHeight;
8091 that.position.top = op.top - oy;
8093 newHeight = gridY - outerDimensions.height;
8094 that.size.height = newHeight;
8095 that.position.top = op.top + os.height - newHeight;
8097 if ( newWidth - gridX > 0 ) {
8098 that.size.width = newWidth;
8099 that.position.left = op.left - ox;
8101 newWidth = gridX - outerDimensions.width;
8102 that.size.width = newWidth;
8103 that.position.left = op.left + os.width - newWidth;
8110 var resizable = $.ui.resizable;
8114 * jQuery UI Dialog 1.11.3
8115 * http://jqueryui.com
8117 * Copyright jQuery Foundation and other contributors
8118 * Released under the MIT license.
8119 * http://jquery.org/license
8121 * http://api.jqueryui.com/dialog/
8125 var dialog = $.widget( "ui.dialog", {
8131 closeOnEscape: true,
8147 // Ensure the titlebar is always visible
8148 using: function( pos ) {
8149 var topOffset = $( this ).css( pos ).offset().top;
8150 if ( topOffset < 0 ) {
8151 $( this ).css( "top", pos.top - topOffset );
8173 sizeRelatedOptions: {
8183 resizableRelatedOptions: {
8190 _create: function() {
8191 this.originalCss = {
8192 display: this.element[ 0 ].style.display,
8193 width: this.element[ 0 ].style.width,
8194 minHeight: this.element[ 0 ].style.minHeight,
8195 maxHeight: this.element[ 0 ].style.maxHeight,
8196 height: this.element[ 0 ].style.height
8198 this.originalPosition = {
8199 parent: this.element.parent(),
8200 index: this.element.parent().children().index( this.element )
8202 this.originalTitle = this.element.attr( "title" );
8203 this.options.title = this.options.title || this.originalTitle;
8205 this._createWrapper();
8209 .removeAttr( "title" )
8210 .addClass( "ui-dialog-content ui-widget-content" )
8211 .appendTo( this.uiDialog );
8213 this._createTitlebar();
8214 this._createButtonPane();
8216 if ( this.options.draggable && $.fn.draggable ) {
8217 this._makeDraggable();
8219 if ( this.options.resizable && $.fn.resizable ) {
8220 this._makeResizable();
8223 this._isOpen = false;
8229 if ( this.options.autoOpen ) {
8234 _appendTo: function() {
8235 var element = this.options.appendTo;
8236 if ( element && (element.jquery || element.nodeType) ) {
8237 return $( element );
8239 return this.document.find( element || "body" ).eq( 0 );
8242 _destroy: function() {
8244 originalPosition = this.originalPosition;
8246 this._destroyOverlay();
8250 .removeClass( "ui-dialog-content ui-widget-content" )
8251 .css( this.originalCss )
8252 // Without detaching first, the following becomes really slow
8255 this.uiDialog.stop( true, true ).remove();
8257 if ( this.originalTitle ) {
8258 this.element.attr( "title", this.originalTitle );
8261 next = originalPosition.parent.children().eq( originalPosition.index );
8262 // Don't try to place the dialog next to itself (#8613)
8263 if ( next.length && next[ 0 ] !== this.element[ 0 ] ) {
8264 next.before( this.element );
8266 originalPosition.parent.append( this.element );
8270 widget: function() {
8271 return this.uiDialog;
8277 close: function( event ) {
8281 if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) {
8285 this._isOpen = false;
8286 this._focusedElement = null;
8287 this._destroyOverlay();
8288 this._untrackInstance();
8290 if ( !this.opener.filter( ":focusable" ).focus().length ) {
8293 // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
8295 activeElement = this.document[ 0 ].activeElement;
8297 // Support: IE9, IE10
8298 // If the <body> is blurred, IE will switch windows, see #4520
8299 if ( activeElement && activeElement.nodeName.toLowerCase() !== "body" ) {
8301 // Hiding a focused element doesn't trigger blur in WebKit
8302 // so in case we have nothing to focus on, explicitly blur the active element
8303 // https://bugs.webkit.org/show_bug.cgi?id=47182
8304 $( activeElement ).blur();
8306 } catch ( error ) {}
8309 this._hide( this.uiDialog, this.options.hide, function() {
8310 that._trigger( "close", event );
8314 isOpen: function() {
8315 return this._isOpen;
8318 moveToTop: function() {
8322 _moveToTop: function( event, silent ) {
8324 zIndicies = this.uiDialog.siblings( ".ui-front:visible" ).map(function() {
8325 return +$( this ).css( "z-index" );
8327 zIndexMax = Math.max.apply( null, zIndicies );
8329 if ( zIndexMax >= +this.uiDialog.css( "z-index" ) ) {
8330 this.uiDialog.css( "z-index", zIndexMax + 1 );
8334 if ( moved && !silent ) {
8335 this._trigger( "focus", event );
8342 if ( this._isOpen ) {
8343 if ( this._moveToTop() ) {
8344 this._focusTabbable();
8349 this._isOpen = true;
8350 this.opener = $( this.document[ 0 ].activeElement );
8354 this._createOverlay();
8355 this._moveToTop( null, true );
8357 // Ensure the overlay is moved to the top with the dialog, but only when
8358 // opening. The overlay shouldn't move after the dialog is open so that
8359 // modeless dialogs opened after the modal dialog stack properly.
8360 if ( this.overlay ) {
8361 this.overlay.css( "z-index", this.uiDialog.css( "z-index" ) - 1 );
8364 this._show( this.uiDialog, this.options.show, function() {
8365 that._focusTabbable();
8366 that._trigger( "focus" );
8369 // Track the dialog immediately upon openening in case a focus event
8370 // somehow occurs outside of the dialog before an element inside the
8371 // dialog is focused (#10152)
8372 this._makeFocusTarget();
8374 this._trigger( "open" );
8377 _focusTabbable: function() {
8378 // Set focus to the first match:
8379 // 1. An element that was focused previously
8380 // 2. First element inside the dialog matching [autofocus]
8381 // 3. Tabbable element inside the content element
8382 // 4. Tabbable element inside the buttonpane
8383 // 5. The close button
8384 // 6. The dialog itself
8385 var hasFocus = this._focusedElement;
8387 hasFocus = this.element.find( "[autofocus]" );
8389 if ( !hasFocus.length ) {
8390 hasFocus = this.element.find( ":tabbable" );
8392 if ( !hasFocus.length ) {
8393 hasFocus = this.uiDialogButtonPane.find( ":tabbable" );
8395 if ( !hasFocus.length ) {
8396 hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" );
8398 if ( !hasFocus.length ) {
8399 hasFocus = this.uiDialog;
8401 hasFocus.eq( 0 ).focus();
8404 _keepFocus: function( event ) {
8405 function checkFocus() {
8406 var activeElement = this.document[0].activeElement,
8407 isActive = this.uiDialog[0] === activeElement ||
8408 $.contains( this.uiDialog[0], activeElement );
8410 this._focusTabbable();
8413 event.preventDefault();
8414 checkFocus.call( this );
8416 // IE <= 8 doesn't prevent moving focus even with event.preventDefault()
8417 // so we check again later
8418 this._delay( checkFocus );
8421 _createWrapper: function() {
8422 this.uiDialog = $("<div>")
8423 .addClass( "ui-dialog ui-widget ui-widget-content ui-corner-all ui-front " +
8424 this.options.dialogClass )
8427 // Setting tabIndex makes the div focusable
8431 .appendTo( this._appendTo() );
8433 this._on( this.uiDialog, {
8434 keydown: function( event ) {
8435 if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
8436 event.keyCode === $.ui.keyCode.ESCAPE ) {
8437 event.preventDefault();
8438 this.close( event );
8442 // prevent tabbing out of dialogs
8443 if ( event.keyCode !== $.ui.keyCode.TAB || event.isDefaultPrevented() ) {
8446 var tabbables = this.uiDialog.find( ":tabbable" ),
8447 first = tabbables.filter( ":first" ),
8448 last = tabbables.filter( ":last" );
8450 if ( ( event.target === last[0] || event.target === this.uiDialog[0] ) && !event.shiftKey ) {
8451 this._delay(function() {
8454 event.preventDefault();
8455 } else if ( ( event.target === first[0] || event.target === this.uiDialog[0] ) && event.shiftKey ) {
8456 this._delay(function() {
8459 event.preventDefault();
8462 mousedown: function( event ) {
8463 if ( this._moveToTop( event ) ) {
8464 this._focusTabbable();
8469 // We assume that any existing aria-describedby attribute means
8470 // that the dialog content is marked up properly
8471 // otherwise we brute force the content as the description
8472 if ( !this.element.find( "[aria-describedby]" ).length ) {
8473 this.uiDialog.attr({
8474 "aria-describedby": this.element.uniqueId().attr( "id" )
8479 _createTitlebar: function() {
8482 this.uiDialogTitlebar = $( "<div>" )
8483 .addClass( "ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix" )
8484 .prependTo( this.uiDialog );
8485 this._on( this.uiDialogTitlebar, {
8486 mousedown: function( event ) {
8487 // Don't prevent click on close button (#8838)
8488 // Focusing a dialog that is partially scrolled out of view
8489 // causes the browser to scroll it into view, preventing the click event
8490 if ( !$( event.target ).closest( ".ui-dialog-titlebar-close" ) ) {
8491 // Dialog isn't getting focus when dragging (#8063)
8492 this.uiDialog.focus();
8498 // Use type="button" to prevent enter keypresses in textboxes from closing the
8499 // dialog in IE (#9312)
8500 this.uiDialogTitlebarClose = $( "<button type='button'></button>" )
8502 label: this.options.closeText,
8504 primary: "ui-icon-closethick"
8508 .addClass( "ui-dialog-titlebar-close" )
8509 .appendTo( this.uiDialogTitlebar );
8510 this._on( this.uiDialogTitlebarClose, {
8511 click: function( event ) {
8512 event.preventDefault();
8513 this.close( event );
8517 uiDialogTitle = $( "<span>" )
8519 .addClass( "ui-dialog-title" )
8520 .prependTo( this.uiDialogTitlebar );
8521 this._title( uiDialogTitle );
8523 this.uiDialog.attr({
8524 "aria-labelledby": uiDialogTitle.attr( "id" )
8528 _title: function( title ) {
8529 if ( !this.options.title ) {
8530 title.html( " " );
8532 title.text( this.options.title );
8535 _createButtonPane: function() {
8536 this.uiDialogButtonPane = $( "<div>" )
8537 .addClass( "ui-dialog-buttonpane ui-widget-content ui-helper-clearfix" );
8539 this.uiButtonSet = $( "<div>" )
8540 .addClass( "ui-dialog-buttonset" )
8541 .appendTo( this.uiDialogButtonPane );
8543 this._createButtons();
8546 _createButtons: function() {
8548 buttons = this.options.buttons;
8550 // if we already have a button pane, remove it
8551 this.uiDialogButtonPane.remove();
8552 this.uiButtonSet.empty();
8554 if ( $.isEmptyObject( buttons ) || ($.isArray( buttons ) && !buttons.length) ) {
8555 this.uiDialog.removeClass( "ui-dialog-buttons" );
8559 $.each( buttons, function( name, props ) {
8560 var click, buttonOptions;
8561 props = $.isFunction( props ) ?
8562 { click: props, text: name } :
8564 // Default to a non-submitting button
8565 props = $.extend( { type: "button" }, props );
8566 // Change the context for the click callback to be the main element
8567 click = props.click;
8568 props.click = function() {
8569 click.apply( that.element[ 0 ], arguments );
8573 text: props.showText
8576 delete props.showText;
8577 $( "<button></button>", props )
8578 .button( buttonOptions )
8579 .appendTo( that.uiButtonSet );
8581 this.uiDialog.addClass( "ui-dialog-buttons" );
8582 this.uiDialogButtonPane.appendTo( this.uiDialog );
8585 _makeDraggable: function() {
8587 options = this.options;
8589 function filteredUi( ui ) {
8591 position: ui.position,
8596 this.uiDialog.draggable({
8597 cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
8598 handle: ".ui-dialog-titlebar",
8599 containment: "document",
8600 start: function( event, ui ) {
8601 $( this ).addClass( "ui-dialog-dragging" );
8602 that._blockFrames();
8603 that._trigger( "dragStart", event, filteredUi( ui ) );
8605 drag: function( event, ui ) {
8606 that._trigger( "drag", event, filteredUi( ui ) );
8608 stop: function( event, ui ) {
8609 var left = ui.offset.left - that.document.scrollLeft(),
8610 top = ui.offset.top - that.document.scrollTop();
8612 options.position = {
8614 at: "left" + (left >= 0 ? "+" : "") + left + " " +
8615 "top" + (top >= 0 ? "+" : "") + top,
8618 $( this ).removeClass( "ui-dialog-dragging" );
8619 that._unblockFrames();
8620 that._trigger( "dragStop", event, filteredUi( ui ) );
8625 _makeResizable: function() {
8627 options = this.options,
8628 handles = options.resizable,
8629 // .ui-resizable has position: relative defined in the stylesheet
8630 // but dialogs have to use absolute or fixed positioning
8631 position = this.uiDialog.css("position"),
8632 resizeHandles = typeof handles === "string" ?
8634 "n,e,s,w,se,sw,ne,nw";
8636 function filteredUi( ui ) {
8638 originalPosition: ui.originalPosition,
8639 originalSize: ui.originalSize,
8640 position: ui.position,
8645 this.uiDialog.resizable({
8646 cancel: ".ui-dialog-content",
8647 containment: "document",
8648 alsoResize: this.element,
8649 maxWidth: options.maxWidth,
8650 maxHeight: options.maxHeight,
8651 minWidth: options.minWidth,
8652 minHeight: this._minHeight(),
8653 handles: resizeHandles,
8654 start: function( event, ui ) {
8655 $( this ).addClass( "ui-dialog-resizing" );
8656 that._blockFrames();
8657 that._trigger( "resizeStart", event, filteredUi( ui ) );
8659 resize: function( event, ui ) {
8660 that._trigger( "resize", event, filteredUi( ui ) );
8662 stop: function( event, ui ) {
8663 var offset = that.uiDialog.offset(),
8664 left = offset.left - that.document.scrollLeft(),
8665 top = offset.top - that.document.scrollTop();
8667 options.height = that.uiDialog.height();
8668 options.width = that.uiDialog.width();
8669 options.position = {
8671 at: "left" + (left >= 0 ? "+" : "") + left + " " +
8672 "top" + (top >= 0 ? "+" : "") + top,
8675 $( this ).removeClass( "ui-dialog-resizing" );
8676 that._unblockFrames();
8677 that._trigger( "resizeStop", event, filteredUi( ui ) );
8680 .css( "position", position );
8683 _trackFocus: function() {
8684 this._on( this.widget(), {
8685 focusin: function( event ) {
8686 this._makeFocusTarget();
8687 this._focusedElement = $( event.target );
8692 _makeFocusTarget: function() {
8693 this._untrackInstance();
8694 this._trackingInstances().unshift( this );
8697 _untrackInstance: function() {
8698 var instances = this._trackingInstances(),
8699 exists = $.inArray( this, instances );
8700 if ( exists !== -1 ) {
8701 instances.splice( exists, 1 );
8705 _trackingInstances: function() {
8706 var instances = this.document.data( "ui-dialog-instances" );
8709 this.document.data( "ui-dialog-instances", instances );
8714 _minHeight: function() {
8715 var options = this.options;
8717 return options.height === "auto" ?
8719 Math.min( options.minHeight, options.height );
8722 _position: function() {
8723 // Need to show the dialog to get the actual offset in the position plugin
8724 var isVisible = this.uiDialog.is( ":visible" );
8726 this.uiDialog.show();
8728 this.uiDialog.position( this.options.position );
8730 this.uiDialog.hide();
8734 _setOptions: function( options ) {
8737 resizableOptions = {};
8739 $.each( options, function( key, value ) {
8740 that._setOption( key, value );
8742 if ( key in that.sizeRelatedOptions ) {
8745 if ( key in that.resizableRelatedOptions ) {
8746 resizableOptions[ key ] = value;
8754 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
8755 this.uiDialog.resizable( "option", resizableOptions );
8759 _setOption: function( key, value ) {
8760 var isDraggable, isResizable,
8761 uiDialog = this.uiDialog;
8763 if ( key === "dialogClass" ) {
8765 .removeClass( this.options.dialogClass )
8769 if ( key === "disabled" ) {
8773 this._super( key, value );
8775 if ( key === "appendTo" ) {
8776 this.uiDialog.appendTo( this._appendTo() );
8779 if ( key === "buttons" ) {
8780 this._createButtons();
8783 if ( key === "closeText" ) {
8784 this.uiDialogTitlebarClose.button({
8785 // Ensure that we always pass a string
8790 if ( key === "draggable" ) {
8791 isDraggable = uiDialog.is( ":data(ui-draggable)" );
8792 if ( isDraggable && !value ) {
8793 uiDialog.draggable( "destroy" );
8796 if ( !isDraggable && value ) {
8797 this._makeDraggable();
8801 if ( key === "position" ) {
8805 if ( key === "resizable" ) {
8806 // currently resizable, becoming non-resizable
8807 isResizable = uiDialog.is( ":data(ui-resizable)" );
8808 if ( isResizable && !value ) {
8809 uiDialog.resizable( "destroy" );
8812 // currently resizable, changing handles
8813 if ( isResizable && typeof value === "string" ) {
8814 uiDialog.resizable( "option", "handles", value );
8817 // currently non-resizable, becoming resizable
8818 if ( !isResizable && value !== false ) {
8819 this._makeResizable();
8823 if ( key === "title" ) {
8824 this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) );
8829 // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
8830 // divs will both have width and height set, so we need to reset them
8831 var nonContentHeight, minContentHeight, maxContentHeight,
8832 options = this.options;
8834 // Reset content sizing
8835 this.element.show().css({
8842 if ( options.minWidth > options.width ) {
8843 options.width = options.minWidth;
8846 // reset wrapper sizing
8847 // determine the height of all the non-content elements
8848 nonContentHeight = this.uiDialog.css({
8850 width: options.width
8853 minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
8854 maxContentHeight = typeof options.maxHeight === "number" ?
8855 Math.max( 0, options.maxHeight - nonContentHeight ) :
8858 if ( options.height === "auto" ) {
8860 minHeight: minContentHeight,
8861 maxHeight: maxContentHeight,
8865 this.element.height( Math.max( 0, options.height - nonContentHeight ) );
8868 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
8869 this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
8873 _blockFrames: function() {
8874 this.iframeBlocks = this.document.find( "iframe" ).map(function() {
8875 var iframe = $( this );
8879 position: "absolute",
8880 width: iframe.outerWidth(),
8881 height: iframe.outerHeight()
8883 .appendTo( iframe.parent() )
8884 .offset( iframe.offset() )[0];
8888 _unblockFrames: function() {
8889 if ( this.iframeBlocks ) {
8890 this.iframeBlocks.remove();
8891 delete this.iframeBlocks;
8895 _allowInteraction: function( event ) {
8896 if ( $( event.target ).closest( ".ui-dialog" ).length ) {
8900 // TODO: Remove hack when datepicker implements
8901 // the .ui-front logic (#8989)
8902 return !!$( event.target ).closest( ".ui-datepicker" ).length;
8905 _createOverlay: function() {
8906 if ( !this.options.modal ) {
8910 // We use a delay in case the overlay is created from an
8911 // event that we're going to be cancelling (#2804)
8912 var isOpening = true;
8913 this._delay(function() {
8917 if ( !this.document.data( "ui-dialog-overlays" ) ) {
8919 // Prevent use of anchors and inputs
8920 // Using _on() for an event handler shared across many instances is
8921 // safe because the dialogs stack and must be closed in reverse order
8922 this._on( this.document, {
8923 focusin: function( event ) {
8928 if ( !this._allowInteraction( event ) ) {
8929 event.preventDefault();
8930 this._trackingInstances()[ 0 ]._focusTabbable();
8936 this.overlay = $( "<div>" )
8937 .addClass( "ui-widget-overlay ui-front" )
8938 .appendTo( this._appendTo() );
8939 this._on( this.overlay, {
8940 mousedown: "_keepFocus"
8942 this.document.data( "ui-dialog-overlays",
8943 (this.document.data( "ui-dialog-overlays" ) || 0) + 1 );
8946 _destroyOverlay: function() {
8947 if ( !this.options.modal ) {
8951 if ( this.overlay ) {
8952 var overlays = this.document.data( "ui-dialog-overlays" ) - 1;
8956 .unbind( "focusin" )
8957 .removeData( "ui-dialog-overlays" );
8959 this.document.data( "ui-dialog-overlays", overlays );
8962 this.overlay.remove();
8963 this.overlay = null;
8970 * jQuery UI Droppable 1.11.3
8971 * http://jqueryui.com
8973 * Copyright jQuery Foundation and other contributors
8974 * Released under the MIT license.
8975 * http://jquery.org/license
8977 * http://api.jqueryui.com/droppable/
8981 $.widget( "ui.droppable", {
8983 widgetEventPrefix: "drop",
8991 tolerance: "intersect",
9000 _create: function() {
9006 this.isover = false;
9009 this.accept = $.isFunction( accept ) ? accept : function( d ) {
9010 return d.is( accept );
9013 this.proportions = function( /* valueToWrite */ ) {
9014 if ( arguments.length ) {
9015 // Store the droppable's proportions
9016 proportions = arguments[ 0 ];
9018 // Retrieve or derive the droppable's proportions
9019 return proportions ?
9022 width: this.element[ 0 ].offsetWidth,
9023 height: this.element[ 0 ].offsetHeight
9028 this._addToManager( o.scope );
9030 o.addClasses && this.element.addClass( "ui-droppable" );
9034 _addToManager: function( scope ) {
9035 // Add the reference and positions to the manager
9036 $.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || [];
9037 $.ui.ddmanager.droppables[ scope ].push( this );
9040 _splice: function( drop ) {
9042 for ( ; i < drop.length; i++ ) {
9043 if ( drop[ i ] === this ) {
9044 drop.splice( i, 1 );
9049 _destroy: function() {
9050 var drop = $.ui.ddmanager.droppables[ this.options.scope ];
9052 this._splice( drop );
9054 this.element.removeClass( "ui-droppable ui-droppable-disabled" );
9057 _setOption: function( key, value ) {
9059 if ( key === "accept" ) {
9060 this.accept = $.isFunction( value ) ? value : function( d ) {
9061 return d.is( value );
9063 } else if ( key === "scope" ) {
9064 var drop = $.ui.ddmanager.droppables[ this.options.scope ];
9066 this._splice( drop );
9067 this._addToManager( value );
9070 this._super( key, value );
9073 _activate: function( event ) {
9074 var draggable = $.ui.ddmanager.current;
9075 if ( this.options.activeClass ) {
9076 this.element.addClass( this.options.activeClass );
9079 this._trigger( "activate", event, this.ui( draggable ) );
9083 _deactivate: function( event ) {
9084 var draggable = $.ui.ddmanager.current;
9085 if ( this.options.activeClass ) {
9086 this.element.removeClass( this.options.activeClass );
9089 this._trigger( "deactivate", event, this.ui( draggable ) );
9093 _over: function( event ) {
9095 var draggable = $.ui.ddmanager.current;
9097 // Bail if draggable and droppable are same element
9098 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
9102 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
9103 if ( this.options.hoverClass ) {
9104 this.element.addClass( this.options.hoverClass );
9106 this._trigger( "over", event, this.ui( draggable ) );
9111 _out: function( event ) {
9113 var draggable = $.ui.ddmanager.current;
9115 // Bail if draggable and droppable are same element
9116 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
9120 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
9121 if ( this.options.hoverClass ) {
9122 this.element.removeClass( this.options.hoverClass );
9124 this._trigger( "out", event, this.ui( draggable ) );
9129 _drop: function( event, custom ) {
9131 var draggable = custom || $.ui.ddmanager.current,
9132 childrenIntersection = false;
9134 // Bail if draggable and droppable are same element
9135 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
9139 this.element.find( ":data(ui-droppable)" ).not( ".ui-draggable-dragging" ).each(function() {
9140 var inst = $( this ).droppable( "instance" );
9142 inst.options.greedy &&
9143 !inst.options.disabled &&
9144 inst.options.scope === draggable.options.scope &&
9145 inst.accept.call( inst.element[ 0 ], ( draggable.currentItem || draggable.element ) ) &&
9146 $.ui.intersect( draggable, $.extend( inst, { offset: inst.element.offset() } ), inst.options.tolerance, event )
9147 ) { childrenIntersection = true; return false; }
9149 if ( childrenIntersection ) {
9153 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
9154 if ( this.options.activeClass ) {
9155 this.element.removeClass( this.options.activeClass );
9157 if ( this.options.hoverClass ) {
9158 this.element.removeClass( this.options.hoverClass );
9160 this._trigger( "drop", event, this.ui( draggable ) );
9161 return this.element;
9170 draggable: ( c.currentItem || c.element ),
9172 position: c.position,
9173 offset: c.positionAbs
9179 $.ui.intersect = (function() {
9180 function isOverAxis( x, reference, size ) {
9181 return ( x >= reference ) && ( x < ( reference + size ) );
9184 return function( draggable, droppable, toleranceMode, event ) {
9186 if ( !droppable.offset ) {
9190 var x1 = ( draggable.positionAbs || draggable.position.absolute ).left + draggable.margins.left,
9191 y1 = ( draggable.positionAbs || draggable.position.absolute ).top + draggable.margins.top,
9192 x2 = x1 + draggable.helperProportions.width,
9193 y2 = y1 + draggable.helperProportions.height,
9194 l = droppable.offset.left,
9195 t = droppable.offset.top,
9196 r = l + droppable.proportions().width,
9197 b = t + droppable.proportions().height;
9199 switch ( toleranceMode ) {
9201 return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b );
9203 return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half
9204 x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half
9205 t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half
9206 y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half
9208 return isOverAxis( event.pageY, t, droppable.proportions().height ) && isOverAxis( event.pageX, l, droppable.proportions().width );
9211 ( y1 >= t && y1 <= b ) || // Top edge touching
9212 ( y2 >= t && y2 <= b ) || // Bottom edge touching
9213 ( y1 < t && y2 > b ) // Surrounded vertically
9215 ( x1 >= l && x1 <= r ) || // Left edge touching
9216 ( x2 >= l && x2 <= r ) || // Right edge touching
9217 ( x1 < l && x2 > r ) // Surrounded horizontally
9226 This manager tracks offsets of draggables and droppables
9230 droppables: { "default": [] },
9231 prepareOffsets: function( t, event ) {
9234 m = $.ui.ddmanager.droppables[ t.options.scope ] || [],
9235 type = event ? event.type : null, // workaround for #2317
9236 list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack();
9238 droppablesLoop: for ( i = 0; i < m.length; i++ ) {
9240 // No disabled and non-accepted
9241 if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ], ( t.currentItem || t.element ) ) ) ) {
9245 // Filter out elements in the current dragged item
9246 for ( j = 0; j < list.length; j++ ) {
9247 if ( list[ j ] === m[ i ].element[ 0 ] ) {
9248 m[ i ].proportions().height = 0;
9249 continue droppablesLoop;
9253 m[ i ].visible = m[ i ].element.css( "display" ) !== "none";
9254 if ( !m[ i ].visible ) {
9258 // Activate the droppable if used directly from draggables
9259 if ( type === "mousedown" ) {
9260 m[ i ]._activate.call( m[ i ], event );
9263 m[ i ].offset = m[ i ].element.offset();
9264 m[ i ].proportions({ width: m[ i ].element[ 0 ].offsetWidth, height: m[ i ].element[ 0 ].offsetHeight });
9269 drop: function( draggable, event ) {
9271 var dropped = false;
9272 // Create a copy of the droppables in case the list changes during the drop (#9116)
9273 $.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() {
9275 if ( !this.options ) {
9278 if ( !this.options.disabled && this.visible && $.ui.intersect( draggable, this, this.options.tolerance, event ) ) {
9279 dropped = this._drop.call( this, event ) || dropped;
9282 if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
9284 this.isover = false;
9285 this._deactivate.call( this, event );
9292 dragStart: function( draggable, event ) {
9293 // Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003)
9294 draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() {
9295 if ( !draggable.options.refreshPositions ) {
9296 $.ui.ddmanager.prepareOffsets( draggable, event );
9300 drag: function( draggable, event ) {
9302 // If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
9303 if ( draggable.options.refreshPositions ) {
9304 $.ui.ddmanager.prepareOffsets( draggable, event );
9307 // Run through all droppables and check their positions based on specific tolerance options
9308 $.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() {
9310 if ( this.options.disabled || this.greedyChild || !this.visible ) {
9314 var parentInstance, scope, parent,
9315 intersects = $.ui.intersect( draggable, this, this.options.tolerance, event ),
9316 c = !intersects && this.isover ? "isout" : ( intersects && !this.isover ? "isover" : null );
9321 if ( this.options.greedy ) {
9322 // find droppable parents with same scope
9323 scope = this.options.scope;
9324 parent = this.element.parents( ":data(ui-droppable)" ).filter(function() {
9325 return $( this ).droppable( "instance" ).options.scope === scope;
9328 if ( parent.length ) {
9329 parentInstance = $( parent[ 0 ] ).droppable( "instance" );
9330 parentInstance.greedyChild = ( c === "isover" );
9334 // we just moved into a greedy child
9335 if ( parentInstance && c === "isover" ) {
9336 parentInstance.isover = false;
9337 parentInstance.isout = true;
9338 parentInstance._out.call( parentInstance, event );
9342 this[c === "isout" ? "isover" : "isout"] = false;
9343 this[c === "isover" ? "_over" : "_out"].call( this, event );
9345 // we just moved out of a greedy child
9346 if ( parentInstance && c === "isout" ) {
9347 parentInstance.isout = false;
9348 parentInstance.isover = true;
9349 parentInstance._over.call( parentInstance, event );
9354 dragStop: function( draggable, event ) {
9355 draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" );
9356 // Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003)
9357 if ( !draggable.options.refreshPositions ) {
9358 $.ui.ddmanager.prepareOffsets( draggable, event );
9363 var droppable = $.ui.droppable;
9367 * jQuery UI Effects 1.11.3
9368 * http://jqueryui.com
9370 * Copyright jQuery Foundation and other contributors
9371 * Released under the MIT license.
9372 * http://jquery.org/license
9374 * http://api.jqueryui.com/category/effects-core/
9378 var dataSpace = "ui-effects-",
9380 // Create a local jQuery because jQuery Color relies on it and the
9381 // global may not exist with AMD and a custom build (#10199)
9389 * jQuery Color Animations v2.1.2
9390 * https://github.com/jquery/jquery-color
9392 * Copyright 2014 jQuery Foundation and other contributors
9393 * Released under the MIT license.
9394 * http://jquery.org/license
9396 * Date: Wed Jan 16 08:47:09 2013 -0600
9398 (function( jQuery, undefined ) {
9400 var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
9402 // plusequals test for += 100 -= 100
9403 rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
9404 // a set of RE's that can match strings and generate color tuples.
9406 re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
9407 parse: function( execResult ) {
9416 re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
9417 parse: function( execResult ) {
9419 execResult[ 1 ] * 2.55,
9420 execResult[ 2 ] * 2.55,
9421 execResult[ 3 ] * 2.55,
9426 // this regex ignores A-F because it's compared against an already lowercased string
9427 re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
9428 parse: function( execResult ) {
9430 parseInt( execResult[ 1 ], 16 ),
9431 parseInt( execResult[ 2 ], 16 ),
9432 parseInt( execResult[ 3 ], 16 )
9436 // this regex ignores A-F because it's compared against an already lowercased string
9437 re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
9438 parse: function( execResult ) {
9440 parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
9441 parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
9442 parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
9446 re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
9448 parse: function( execResult ) {
9451 execResult[ 2 ] / 100,
9452 execResult[ 3 ] / 100,
9459 color = jQuery.Color = function( color, green, blue, alpha ) {
9460 return new jQuery.Color.fn.parse( color, green, blue, alpha );
9510 support = color.support = {},
9512 // element for support tests
9513 supportElem = jQuery( "<p>" )[ 0 ],
9515 // colors = jQuery.Color.names
9518 // local aliases of functions called often
9521 // determine rgba support immediately
9522 supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
9523 support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
9525 // define cache name and alpha properties
9526 // for rgba and hsla spaces
9527 each( spaces, function( spaceName, space ) {
9528 space.cache = "_" + spaceName;
9529 space.props.alpha = {
9536 function clamp( value, prop, allowEmpty ) {
9537 var type = propTypes[ prop.type ] || {};
9539 if ( value == null ) {
9540 return (allowEmpty || !prop.def) ? null : prop.def;
9543 // ~~ is an short way of doing floor for positive numbers
9544 value = type.floor ? ~~value : parseFloat( value );
9546 // IE will pass in empty strings as value for alpha,
9547 // which will hit this case
9548 if ( isNaN( value ) ) {
9553 // we add mod before modding to make sure that negatives values
9554 // get converted properly: -10 -> 350
9555 return (value + type.mod) % type.mod;
9558 // for now all property types without mod have min and max
9559 return 0 > value ? 0 : type.max < value ? type.max : value;
9562 function stringParse( string ) {
9564 rgba = inst._rgba = [];
9566 string = string.toLowerCase();
9568 each( stringParsers, function( i, parser ) {
9570 match = parser.re.exec( string ),
9571 values = match && parser.parse( match ),
9572 spaceName = parser.space || "rgba";
9575 parsed = inst[ spaceName ]( values );
9577 // if this was an rgba parse the assignment might happen twice
9579 inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
9580 rgba = inst._rgba = parsed._rgba;
9582 // exit each( stringParsers ) here because we matched
9587 // Found a stringParser that handled it
9588 if ( rgba.length ) {
9590 // if this came from a parsed string, force "transparent" when alpha is 0
9591 // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
9592 if ( rgba.join() === "0,0,0,0" ) {
9593 jQuery.extend( rgba, colors.transparent );
9599 return colors[ string ];
9602 color.fn = jQuery.extend( color.prototype, {
9603 parse: function( red, green, blue, alpha ) {
9604 if ( red === undefined ) {
9605 this._rgba = [ null, null, null, null ];
9608 if ( red.jquery || red.nodeType ) {
9609 red = jQuery( red ).css( green );
9614 type = jQuery.type( red ),
9615 rgba = this._rgba = [];
9617 // more than 1 argument specified - assume ( red, green, blue, alpha )
9618 if ( green !== undefined ) {
9619 red = [ red, green, blue, alpha ];
9623 if ( type === "string" ) {
9624 return this.parse( stringParse( red ) || colors._default );
9627 if ( type === "array" ) {
9628 each( spaces.rgba.props, function( key, prop ) {
9629 rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
9634 if ( type === "object" ) {
9635 if ( red instanceof color ) {
9636 each( spaces, function( spaceName, space ) {
9637 if ( red[ space.cache ] ) {
9638 inst[ space.cache ] = red[ space.cache ].slice();
9642 each( spaces, function( spaceName, space ) {
9643 var cache = space.cache;
9644 each( space.props, function( key, prop ) {
9646 // if the cache doesn't exist, and we know how to convert
9647 if ( !inst[ cache ] && space.to ) {
9649 // if the value was null, we don't need to copy it
9650 // if the key was alpha, we don't need to copy it either
9651 if ( key === "alpha" || red[ key ] == null ) {
9654 inst[ cache ] = space.to( inst._rgba );
9657 // this is the only case where we allow nulls for ALL properties.
9658 // call clamp with alwaysAllowEmpty
9659 inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
9662 // everything defined but alpha?
9663 if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
9664 // use the default of 1
9665 inst[ cache ][ 3 ] = 1;
9667 inst._rgba = space.from( inst[ cache ] );
9675 is: function( compare ) {
9676 var is = color( compare ),
9680 each( spaces, function( _, space ) {
9682 isCache = is[ space.cache ];
9684 localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
9685 each( space.props, function( _, prop ) {
9686 if ( isCache[ prop.idx ] != null ) {
9687 same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
9696 _space: function() {
9699 each( spaces, function( spaceName, space ) {
9700 if ( inst[ space.cache ] ) {
9701 used.push( spaceName );
9706 transition: function( other, distance ) {
9707 var end = color( other ),
9708 spaceName = end._space(),
9709 space = spaces[ spaceName ],
9710 startColor = this.alpha() === 0 ? color( "transparent" ) : this,
9711 start = startColor[ space.cache ] || space.to( startColor._rgba ),
9712 result = start.slice();
9714 end = end[ space.cache ];
9715 each( space.props, function( key, prop ) {
9716 var index = prop.idx,
9717 startValue = start[ index ],
9718 endValue = end[ index ],
9719 type = propTypes[ prop.type ] || {};
9721 // if null, don't override start value
9722 if ( endValue === null ) {
9725 // if null - use end
9726 if ( startValue === null ) {
9727 result[ index ] = endValue;
9730 if ( endValue - startValue > type.mod / 2 ) {
9731 startValue += type.mod;
9732 } else if ( startValue - endValue > type.mod / 2 ) {
9733 startValue -= type.mod;
9736 result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
9739 return this[ spaceName ]( result );
9741 blend: function( opaque ) {
9742 // if we are already opaque - return ourself
9743 if ( this._rgba[ 3 ] === 1 ) {
9747 var rgb = this._rgba.slice(),
9749 blend = color( opaque )._rgba;
9751 return color( jQuery.map( rgb, function( v, i ) {
9752 return ( 1 - a ) * blend[ i ] + a * v;
9755 toRgbaString: function() {
9756 var prefix = "rgba(",
9757 rgba = jQuery.map( this._rgba, function( v, i ) {
9758 return v == null ? ( i > 2 ? 1 : 0 ) : v;
9761 if ( rgba[ 3 ] === 1 ) {
9766 return prefix + rgba.join() + ")";
9768 toHslaString: function() {
9769 var prefix = "hsla(",
9770 hsla = jQuery.map( this.hsla(), function( v, i ) {
9777 v = Math.round( v * 100 ) + "%";
9782 if ( hsla[ 3 ] === 1 ) {
9786 return prefix + hsla.join() + ")";
9788 toHexString: function( includeAlpha ) {
9789 var rgba = this._rgba.slice(),
9792 if ( includeAlpha ) {
9793 rgba.push( ~~( alpha * 255 ) );
9796 return "#" + jQuery.map( rgba, function( v ) {
9798 // default to 0 when nulls exist
9799 v = ( v || 0 ).toString( 16 );
9800 return v.length === 1 ? "0" + v : v;
9803 toString: function() {
9804 return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
9807 color.fn.parse.prototype = color.fn;
9809 // hsla conversions adapted from:
9810 // https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
9812 function hue2rgb( p, q, h ) {
9815 return p + ( q - p ) * h * 6;
9821 return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6;
9826 spaces.hsla.to = function( rgba ) {
9827 if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
9828 return [ null, null, null, rgba[ 3 ] ];
9830 var r = rgba[ 0 ] / 255,
9831 g = rgba[ 1 ] / 255,
9832 b = rgba[ 2 ] / 255,
9834 max = Math.max( r, g, b ),
9835 min = Math.min( r, g, b ),
9841 if ( min === max ) {
9843 } else if ( r === max ) {
9844 h = ( 60 * ( g - b ) / diff ) + 360;
9845 } else if ( g === max ) {
9846 h = ( 60 * ( b - r ) / diff ) + 120;
9848 h = ( 60 * ( r - g ) / diff ) + 240;
9851 // chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
9852 // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
9855 } else if ( l <= 0.5 ) {
9858 s = diff / ( 2 - add );
9860 return [ Math.round(h) % 360, s, l, a == null ? 1 : a ];
9863 spaces.hsla.from = function( hsla ) {
9864 if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
9865 return [ null, null, null, hsla[ 3 ] ];
9867 var h = hsla[ 0 ] / 360,
9871 q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
9875 Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
9876 Math.round( hue2rgb( p, q, h ) * 255 ),
9877 Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
9882 each( spaces, function( spaceName, space ) {
9883 var props = space.props,
9884 cache = space.cache,
9888 // makes rgba() and hsla()
9889 color.fn[ spaceName ] = function( value ) {
9891 // generate a cache for this space if it doesn't exist
9892 if ( to && !this[ cache ] ) {
9893 this[ cache ] = to( this._rgba );
9895 if ( value === undefined ) {
9896 return this[ cache ].slice();
9900 type = jQuery.type( value ),
9901 arr = ( type === "array" || type === "object" ) ? value : arguments,
9902 local = this[ cache ].slice();
9904 each( props, function( key, prop ) {
9905 var val = arr[ type === "object" ? key : prop.idx ];
9906 if ( val == null ) {
9907 val = local[ prop.idx ];
9909 local[ prop.idx ] = clamp( val, prop );
9913 ret = color( from( local ) );
9914 ret[ cache ] = local;
9917 return color( local );
9921 // makes red() green() blue() alpha() hue() saturation() lightness()
9922 each( props, function( key, prop ) {
9923 // alpha is included in more than one space
9924 if ( color.fn[ key ] ) {
9927 color.fn[ key ] = function( value ) {
9928 var vtype = jQuery.type( value ),
9929 fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
9930 local = this[ fn ](),
9931 cur = local[ prop.idx ],
9934 if ( vtype === "undefined" ) {
9938 if ( vtype === "function" ) {
9939 value = value.call( this, cur );
9940 vtype = jQuery.type( value );
9942 if ( value == null && prop.empty ) {
9945 if ( vtype === "string" ) {
9946 match = rplusequals.exec( value );
9948 value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
9951 local[ prop.idx ] = value;
9952 return this[ fn ]( local );
9957 // add cssHook and .fx.step function for each named hook.
9958 // accept a space separated string of properties
9959 color.hook = function( hook ) {
9960 var hooks = hook.split( " " );
9961 each( hooks, function( i, hook ) {
9962 jQuery.cssHooks[ hook ] = {
9963 set: function( elem, value ) {
9964 var parsed, curElem,
9965 backgroundColor = "";
9967 if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) {
9968 value = color( parsed || value );
9969 if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
9970 curElem = hook === "backgroundColor" ? elem.parentNode : elem;
9972 (backgroundColor === "" || backgroundColor === "transparent") &&
9973 curElem && curElem.style
9976 backgroundColor = jQuery.css( curElem, "backgroundColor" );
9977 curElem = curElem.parentNode;
9982 value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
9987 value = value.toRgbaString();
9990 elem.style[ hook ] = value;
9992 // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit'
9996 jQuery.fx.step[ hook ] = function( fx ) {
9997 if ( !fx.colorInit ) {
9998 fx.start = color( fx.elem, hook );
9999 fx.end = color( fx.end );
10000 fx.colorInit = true;
10002 jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
10008 color.hook( stepHooks );
10010 jQuery.cssHooks.borderColor = {
10011 expand: function( value ) {
10014 each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
10015 expanded[ "border" + part + "Color" ] = value;
10021 // Basic color names only.
10022 // Usage of any of the other color names requires adding yourself or including
10023 // jquery.color.svg-names.js.
10024 colors = jQuery.Color.names = {
10025 // 4.1. Basic color keywords
10029 fuchsia: "#ff00ff",
10043 // 4.2.3. "transparent" color keyword
10044 transparent: [ null, null, null, 0 ],
10046 _default: "#ffffff"
10051 /******************************************************************************/
10052 /****************************** CLASS ANIMATIONS ******************************/
10053 /******************************************************************************/
10056 var classAnimationActions = [ "add", "remove", "toggle" ],
10057 shorthandStyles = {
10069 $.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) {
10070 $.fx.step[ prop ] = function( fx ) {
10071 if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
10072 jQuery.style( fx.elem, prop, fx.end );
10078 function getElementStyles( elem ) {
10080 style = elem.ownerDocument.defaultView ?
10081 elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :
10085 if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
10086 len = style.length;
10088 key = style[ len ];
10089 if ( typeof style[ key ] === "string" ) {
10090 styles[ $.camelCase( key ) ] = style[ key ];
10093 // support: Opera, IE <9
10095 for ( key in style ) {
10096 if ( typeof style[ key ] === "string" ) {
10097 styles[ key ] = style[ key ];
10105 function styleDifference( oldStyle, newStyle ) {
10109 for ( name in newStyle ) {
10110 value = newStyle[ name ];
10111 if ( oldStyle[ name ] !== value ) {
10112 if ( !shorthandStyles[ name ] ) {
10113 if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
10114 diff[ name ] = value;
10123 // support: jQuery <1.8
10124 if ( !$.fn.addBack ) {
10125 $.fn.addBack = function( selector ) {
10126 return this.add( selector == null ?
10127 this.prevObject : this.prevObject.filter( selector )
10132 $.effects.animateClass = function( value, duration, easing, callback ) {
10133 var o = $.speed( duration, easing, callback );
10135 return this.queue( function() {
10136 var animated = $( this ),
10137 baseClass = animated.attr( "class" ) || "",
10139 allAnimations = o.children ? animated.find( "*" ).addBack() : animated;
10141 // map the animated objects to store the original styles.
10142 allAnimations = allAnimations.map(function() {
10143 var el = $( this );
10146 start: getElementStyles( this )
10150 // apply class change
10151 applyClassChange = function() {
10152 $.each( classAnimationActions, function(i, action) {
10153 if ( value[ action ] ) {
10154 animated[ action + "Class" ]( value[ action ] );
10158 applyClassChange();
10160 // map all animated objects again - calculate new styles and diff
10161 allAnimations = allAnimations.map(function() {
10162 this.end = getElementStyles( this.el[ 0 ] );
10163 this.diff = styleDifference( this.start, this.end );
10167 // apply original class
10168 animated.attr( "class", baseClass );
10170 // map all animated objects again - this time collecting a promise
10171 allAnimations = allAnimations.map(function() {
10172 var styleInfo = this,
10173 dfd = $.Deferred(),
10174 opts = $.extend({}, o, {
10176 complete: function() {
10177 dfd.resolve( styleInfo );
10181 this.el.animate( this.diff, opts );
10182 return dfd.promise();
10185 // once all animations have completed:
10186 $.when.apply( $, allAnimations.get() ).done(function() {
10188 // set the final class
10189 applyClassChange();
10191 // for each animated element,
10192 // clear all css properties that were animated
10193 $.each( arguments, function() {
10195 $.each( this.diff, function(key) {
10200 // this is guarnteed to be there if you use jQuery.speed()
10201 // it also handles dequeuing the next anim...
10202 o.complete.call( animated[ 0 ] );
10208 addClass: (function( orig ) {
10209 return function( classNames, speed, easing, callback ) {
10211 $.effects.animateClass.call( this,
10212 { add: classNames }, speed, easing, callback ) :
10213 orig.apply( this, arguments );
10215 })( $.fn.addClass ),
10217 removeClass: (function( orig ) {
10218 return function( classNames, speed, easing, callback ) {
10219 return arguments.length > 1 ?
10220 $.effects.animateClass.call( this,
10221 { remove: classNames }, speed, easing, callback ) :
10222 orig.apply( this, arguments );
10224 })( $.fn.removeClass ),
10226 toggleClass: (function( orig ) {
10227 return function( classNames, force, speed, easing, callback ) {
10228 if ( typeof force === "boolean" || force === undefined ) {
10230 // without speed parameter
10231 return orig.apply( this, arguments );
10233 return $.effects.animateClass.call( this,
10234 (force ? { add: classNames } : { remove: classNames }),
10235 speed, easing, callback );
10238 // without force parameter
10239 return $.effects.animateClass.call( this,
10240 { toggle: classNames }, force, speed, easing );
10243 })( $.fn.toggleClass ),
10245 switchClass: function( remove, add, speed, easing, callback) {
10246 return $.effects.animateClass.call( this, {
10249 }, speed, easing, callback );
10255 /******************************************************************************/
10256 /*********************************** EFFECTS **********************************/
10257 /******************************************************************************/
10261 $.extend( $.effects, {
10264 // Saves a set of properties in a data storage
10265 save: function( element, set ) {
10266 for ( var i = 0; i < set.length; i++ ) {
10267 if ( set[ i ] !== null ) {
10268 element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
10273 // Restores a set of previously saved properties from a data storage
10274 restore: function( element, set ) {
10276 for ( i = 0; i < set.length; i++ ) {
10277 if ( set[ i ] !== null ) {
10278 val = element.data( dataSpace + set[ i ] );
10279 // support: jQuery 1.6.2
10280 // http://bugs.jquery.com/ticket/9917
10281 // jQuery 1.6.2 incorrectly returns undefined for any falsy value.
10282 // We can't differentiate between "" and 0 here, so we just assume
10283 // empty string since it's likely to be a more common value...
10284 if ( val === undefined ) {
10287 element.css( set[ i ], val );
10292 setMode: function( el, mode ) {
10293 if (mode === "toggle") {
10294 mode = el.is( ":hidden" ) ? "show" : "hide";
10299 // Translates a [top,left] array into a baseline value
10300 // this should be a little more flexible in the future to handle a string & hash
10301 getBaseline: function( origin, original ) {
10303 switch ( origin[ 0 ] ) {
10304 case "top": y = 0; break;
10305 case "middle": y = 0.5; break;
10306 case "bottom": y = 1; break;
10307 default: y = origin[ 0 ] / original.height;
10309 switch ( origin[ 1 ] ) {
10310 case "left": x = 0; break;
10311 case "center": x = 0.5; break;
10312 case "right": x = 1; break;
10313 default: x = origin[ 1 ] / original.width;
10321 // Wraps the element around a wrapper that copies position properties
10322 createWrapper: function( element ) {
10324 // if the element is already wrapped, return it
10325 if ( element.parent().is( ".ui-effects-wrapper" )) {
10326 return element.parent();
10329 // wrap the element
10331 width: element.outerWidth(true),
10332 height: element.outerHeight(true),
10333 "float": element.css( "float" )
10335 wrapper = $( "<div></div>" )
10336 .addClass( "ui-effects-wrapper" )
10339 background: "transparent",
10344 // Store the size in case width/height are defined in % - Fixes #5245
10346 width: element.width(),
10347 height: element.height()
10349 active = document.activeElement;
10351 // support: Firefox
10352 // Firefox incorrectly exposes anonymous content
10353 // https://bugzilla.mozilla.org/show_bug.cgi?id=561664
10357 active = document.body;
10360 element.wrap( wrapper );
10362 // Fixes #7595 - Elements lose focus when wrapped.
10363 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
10364 $( active ).focus();
10367 wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element
10369 // transfer positioning properties to the wrapper
10370 if ( element.css( "position" ) === "static" ) {
10371 wrapper.css({ position: "relative" });
10372 element.css({ position: "relative" });
10375 position: element.css( "position" ),
10376 zIndex: element.css( "z-index" )
10378 $.each([ "top", "left", "bottom", "right" ], function(i, pos) {
10379 props[ pos ] = element.css( pos );
10380 if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
10381 props[ pos ] = "auto";
10385 position: "relative",
10394 return wrapper.css( props ).show();
10397 removeWrapper: function( element ) {
10398 var active = document.activeElement;
10400 if ( element.parent().is( ".ui-effects-wrapper" ) ) {
10401 element.parent().replaceWith( element );
10403 // Fixes #7595 - Elements lose focus when wrapped.
10404 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
10405 $( active ).focus();
10412 setTransition: function( element, list, factor, value ) {
10413 value = value || {};
10414 $.each( list, function( i, x ) {
10415 var unit = element.cssUnit( x );
10416 if ( unit[ 0 ] > 0 ) {
10417 value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
10424 // return an effect options object for the given parameters:
10425 function _normalizeArguments( effect, options, speed, callback ) {
10427 // allow passing all options as the first parameter
10428 if ( $.isPlainObject( effect ) ) {
10430 effect = effect.effect;
10433 // convert to an object
10434 effect = { effect: effect };
10436 // catch (effect, null, ...)
10437 if ( options == null ) {
10441 // catch (effect, callback)
10442 if ( $.isFunction( options ) ) {
10443 callback = options;
10448 // catch (effect, speed, ?)
10449 if ( typeof options === "number" || $.fx.speeds[ options ] ) {
10455 // catch (effect, options, callback)
10456 if ( $.isFunction( speed ) ) {
10461 // add options to effect
10463 $.extend( effect, options );
10466 speed = speed || options.duration;
10467 effect.duration = $.fx.off ? 0 :
10468 typeof speed === "number" ? speed :
10469 speed in $.fx.speeds ? $.fx.speeds[ speed ] :
10470 $.fx.speeds._default;
10472 effect.complete = callback || options.complete;
10477 function standardAnimationOption( option ) {
10478 // Valid standard speeds (nothing, number, named speed)
10479 if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) {
10483 // Invalid strings - treat as "normal" speed
10484 if ( typeof option === "string" && !$.effects.effect[ option ] ) {
10488 // Complete callback
10489 if ( $.isFunction( option ) ) {
10493 // Options hash (but not naming an effect)
10494 if ( typeof option === "object" && !option.effect ) {
10498 // Didn't match any standard API
10503 effect: function( /* effect, options, speed, callback */ ) {
10504 var args = _normalizeArguments.apply( this, arguments ),
10506 queue = args.queue,
10507 effectMethod = $.effects.effect[ args.effect ];
10509 if ( $.fx.off || !effectMethod ) {
10510 // delegate to the original method (e.g., .show()) if possible
10512 return this[ mode ]( args.duration, args.complete );
10514 return this.each( function() {
10515 if ( args.complete ) {
10516 args.complete.call( this );
10522 function run( next ) {
10523 var elem = $( this ),
10524 complete = args.complete,
10528 if ( $.isFunction( complete ) ) {
10529 complete.call( elem[0] );
10531 if ( $.isFunction( next ) ) {
10536 // If the element already has the correct final state, delegate to
10537 // the core methods so the internal tracking of "olddisplay" works.
10538 if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
10542 effectMethod.call( elem[0], args, done );
10546 return queue === false ? this.each( run ) : this.queue( queue || "fx", run );
10549 show: (function( orig ) {
10550 return function( option ) {
10551 if ( standardAnimationOption( option ) ) {
10552 return orig.apply( this, arguments );
10554 var args = _normalizeArguments.apply( this, arguments );
10555 args.mode = "show";
10556 return this.effect.call( this, args );
10561 hide: (function( orig ) {
10562 return function( option ) {
10563 if ( standardAnimationOption( option ) ) {
10564 return orig.apply( this, arguments );
10566 var args = _normalizeArguments.apply( this, arguments );
10567 args.mode = "hide";
10568 return this.effect.call( this, args );
10573 toggle: (function( orig ) {
10574 return function( option ) {
10575 if ( standardAnimationOption( option ) || typeof option === "boolean" ) {
10576 return orig.apply( this, arguments );
10578 var args = _normalizeArguments.apply( this, arguments );
10579 args.mode = "toggle";
10580 return this.effect.call( this, args );
10585 // helper functions
10586 cssUnit: function(key) {
10587 var style = this.css( key ),
10590 $.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
10591 if ( style.indexOf( unit ) > 0 ) {
10592 val = [ parseFloat( style ), unit ];
10601 /******************************************************************************/
10602 /*********************************** EASING ***********************************/
10603 /******************************************************************************/
10607 // based on easing equations from Robert Penner (http://www.robertpenner.com/easing)
10609 var baseEasings = {};
10611 $.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
10612 baseEasings[ name ] = function( p ) {
10613 return Math.pow( p, i + 2 );
10617 $.extend( baseEasings, {
10618 Sine: function( p ) {
10619 return 1 - Math.cos( p * Math.PI / 2 );
10621 Circ: function( p ) {
10622 return 1 - Math.sqrt( 1 - p * p );
10624 Elastic: function( p ) {
10625 return p === 0 || p === 1 ? p :
10626 -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 );
10628 Back: function( p ) {
10629 return p * p * ( 3 * p - 2 );
10631 Bounce: function( p ) {
10635 while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
10636 return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
10640 $.each( baseEasings, function( name, easeIn ) {
10641 $.easing[ "easeIn" + name ] = easeIn;
10642 $.easing[ "easeOut" + name ] = function( p ) {
10643 return 1 - easeIn( 1 - p );
10645 $.easing[ "easeInOut" + name ] = function( p ) {
10647 easeIn( p * 2 ) / 2 :
10648 1 - easeIn( p * -2 + 2 ) / 2;
10654 var effect = $.effects;
10658 * jQuery UI Effects Blind 1.11.3
10659 * http://jqueryui.com
10661 * Copyright jQuery Foundation and other contributors
10662 * Released under the MIT license.
10663 * http://jquery.org/license
10665 * http://api.jqueryui.com/blind-effect/
10669 var effectBlind = $.effects.effect.blind = function( o, done ) {
10671 var el = $( this ),
10672 rvertical = /up|down|vertical/,
10673 rpositivemotion = /up|left|vertical|horizontal/,
10674 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
10675 mode = $.effects.setMode( el, o.mode || "hide" ),
10676 direction = o.direction || "up",
10677 vertical = rvertical.test( direction ),
10678 ref = vertical ? "height" : "width",
10679 ref2 = vertical ? "top" : "left",
10680 motion = rpositivemotion.test( direction ),
10682 show = mode === "show",
10683 wrapper, distance, margin;
10685 // if already wrapped, the wrapper's properties are my property. #6245
10686 if ( el.parent().is( ".ui-effects-wrapper" ) ) {
10687 $.effects.save( el.parent(), props );
10689 $.effects.save( el, props );
10692 wrapper = $.effects.createWrapper( el ).css({
10696 distance = wrapper[ ref ]();
10697 margin = parseFloat( wrapper.css( ref2 ) ) || 0;
10699 animation[ ref ] = show ? distance : 0;
10702 .css( vertical ? "bottom" : "right", 0 )
10703 .css( vertical ? "top" : "left", "auto" )
10704 .css({ position: "absolute" });
10706 animation[ ref2 ] = show ? margin : distance + margin;
10709 // start at 0 if we are showing
10711 wrapper.css( ref, 0 );
10713 wrapper.css( ref2, margin + distance );
10718 wrapper.animate( animation, {
10719 duration: o.duration,
10722 complete: function() {
10723 if ( mode === "hide" ) {
10726 $.effects.restore( el, props );
10727 $.effects.removeWrapper( el );
10735 * jQuery UI Effects Bounce 1.11.3
10736 * http://jqueryui.com
10738 * Copyright jQuery Foundation and other contributors
10739 * Released under the MIT license.
10740 * http://jquery.org/license
10742 * http://api.jqueryui.com/bounce-effect/
10746 var effectBounce = $.effects.effect.bounce = function( o, done ) {
10747 var el = $( this ),
10748 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
10751 mode = $.effects.setMode( el, o.mode || "effect" ),
10752 hide = mode === "hide",
10753 show = mode === "show",
10754 direction = o.direction || "up",
10755 distance = o.distance,
10756 times = o.times || 5,
10758 // number of internal animations
10759 anims = times * 2 + ( show || hide ? 1 : 0 ),
10760 speed = o.duration / anims,
10764 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
10765 motion = ( direction === "up" || direction === "left" ),
10770 // we will need to re-assemble the queue to stack our animations in place
10771 queue = el.queue(),
10772 queuelen = queue.length;
10774 // Avoid touching opacity to prevent clearType and PNG issues in IE
10775 if ( show || hide ) {
10776 props.push( "opacity" );
10779 $.effects.save( el, props );
10781 $.effects.createWrapper( el ); // Create Wrapper
10783 // default distance for the BIGGEST bounce is the outer Distance / 3
10785 distance = el[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
10789 downAnim = { opacity: 1 };
10790 downAnim[ ref ] = 0;
10792 // if we are showing, force opacity 0 and set the initial position
10793 // then do the "first" animation
10794 el.css( "opacity", 0 )
10795 .css( ref, motion ? -distance * 2 : distance * 2 )
10796 .animate( downAnim, speed, easing );
10799 // start at the smallest distance if we are hiding
10801 distance = distance / Math.pow( 2, times - 1 );
10805 downAnim[ ref ] = 0;
10806 // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
10807 for ( i = 0; i < times; i++ ) {
10809 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
10811 el.animate( upAnim, speed, easing )
10812 .animate( downAnim, speed, easing );
10814 distance = hide ? distance * 2 : distance / 2;
10817 // Last Bounce when Hiding
10819 upAnim = { opacity: 0 };
10820 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
10822 el.animate( upAnim, speed, easing );
10825 el.queue(function() {
10829 $.effects.restore( el, props );
10830 $.effects.removeWrapper( el );
10834 // inject all the animations we just queued to be first in line (after "inprogress")
10835 if ( queuelen > 1) {
10836 queue.splice.apply( queue,
10837 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
10845 * jQuery UI Effects Clip 1.11.3
10846 * http://jqueryui.com
10848 * Copyright jQuery Foundation and other contributors
10849 * Released under the MIT license.
10850 * http://jquery.org/license
10852 * http://api.jqueryui.com/clip-effect/
10856 var effectClip = $.effects.effect.clip = function( o, done ) {
10858 var el = $( this ),
10859 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
10860 mode = $.effects.setMode( el, o.mode || "hide" ),
10861 show = mode === "show",
10862 direction = o.direction || "vertical",
10863 vert = direction === "vertical",
10864 size = vert ? "height" : "width",
10865 position = vert ? "top" : "left",
10867 wrapper, animate, distance;
10870 $.effects.save( el, props );
10874 wrapper = $.effects.createWrapper( el ).css({
10877 animate = ( el[0].tagName === "IMG" ) ? wrapper : el;
10878 distance = animate[ size ]();
10882 animate.css( size, 0 );
10883 animate.css( position, distance / 2 );
10886 // Create Animation Object:
10887 animation[ size ] = show ? distance : 0;
10888 animation[ position ] = show ? 0 : distance / 2;
10891 animate.animate( animation, {
10893 duration: o.duration,
10895 complete: function() {
10899 $.effects.restore( el, props );
10900 $.effects.removeWrapper( el );
10909 * jQuery UI Effects Drop 1.11.3
10910 * http://jqueryui.com
10912 * Copyright jQuery Foundation and other contributors
10913 * Released under the MIT license.
10914 * http://jquery.org/license
10916 * http://api.jqueryui.com/drop-effect/
10920 var effectDrop = $.effects.effect.drop = function( o, done ) {
10922 var el = $( this ),
10923 props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ],
10924 mode = $.effects.setMode( el, o.mode || "hide" ),
10925 show = mode === "show",
10926 direction = o.direction || "left",
10927 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
10928 motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg",
10930 opacity: show ? 1 : 0
10935 $.effects.save( el, props );
10937 $.effects.createWrapper( el );
10939 distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ) / 2;
10943 .css( "opacity", 0 )
10944 .css( ref, motion === "pos" ? -distance : distance );
10948 animation[ ref ] = ( show ?
10949 ( motion === "pos" ? "+=" : "-=" ) :
10950 ( motion === "pos" ? "-=" : "+=" ) ) +
10954 el.animate( animation, {
10956 duration: o.duration,
10958 complete: function() {
10959 if ( mode === "hide" ) {
10962 $.effects.restore( el, props );
10963 $.effects.removeWrapper( el );
10971 * jQuery UI Effects Explode 1.11.3
10972 * http://jqueryui.com
10974 * Copyright jQuery Foundation and other contributors
10975 * Released under the MIT license.
10976 * http://jquery.org/license
10978 * http://api.jqueryui.com/explode-effect/
10982 var effectExplode = $.effects.effect.explode = function( o, done ) {
10984 var rows = o.pieces ? Math.round( Math.sqrt( o.pieces ) ) : 3,
10987 mode = $.effects.setMode( el, o.mode || "hide" ),
10988 show = mode === "show",
10990 // show and then visibility:hidden the element before calculating offset
10991 offset = el.show().css( "visibility", "hidden" ).offset(),
10993 // width and height of a piece
10994 width = Math.ceil( el.outerWidth() / cells ),
10995 height = Math.ceil( el.outerHeight() / rows ),
10999 i, j, left, top, mx, my;
11001 // children animate complete:
11002 function childComplete() {
11003 pieces.push( this );
11004 if ( pieces.length === rows * cells ) {
11009 // clone the element for each row and cell.
11010 for ( i = 0; i < rows ; i++ ) { // ===>
11011 top = offset.top + i * height;
11012 my = i - ( rows - 1 ) / 2 ;
11014 for ( j = 0; j < cells ; j++ ) { // |||
11015 left = offset.left + j * width;
11016 mx = j - ( cells - 1 ) / 2 ;
11018 // Create a clone of the now hidden main element that will be absolute positioned
11019 // within a wrapper div off the -left and -top equal to size of our pieces
11022 .appendTo( "body" )
11023 .wrap( "<div></div>" )
11025 position: "absolute",
11026 visibility: "visible",
11031 // select the wrapper - make it overflow: hidden and absolute positioned based on
11032 // where the original was located +left and +top equal to the size of pieces
11034 .addClass( "ui-effects-explode" )
11036 position: "absolute",
11037 overflow: "hidden",
11040 left: left + ( show ? mx * width : 0 ),
11041 top: top + ( show ? my * height : 0 ),
11042 opacity: show ? 0 : 1
11044 left: left + ( show ? 0 : mx * width ),
11045 top: top + ( show ? 0 : my * height ),
11046 opacity: show ? 1 : 0
11047 }, o.duration || 500, o.easing, childComplete );
11051 function animComplete() {
11053 visibility: "visible"
11055 $( pieces ).remove();
11065 * jQuery UI Effects Fade 1.11.3
11066 * http://jqueryui.com
11068 * Copyright jQuery Foundation and other contributors
11069 * Released under the MIT license.
11070 * http://jquery.org/license
11072 * http://api.jqueryui.com/fade-effect/
11076 var effectFade = $.effects.effect.fade = function( o, done ) {
11077 var el = $( this ),
11078 mode = $.effects.setMode( el, o.mode || "toggle" );
11084 duration: o.duration,
11092 * jQuery UI Effects Fold 1.11.3
11093 * http://jqueryui.com
11095 * Copyright jQuery Foundation and other contributors
11096 * Released under the MIT license.
11097 * http://jquery.org/license
11099 * http://api.jqueryui.com/fold-effect/
11103 var effectFold = $.effects.effect.fold = function( o, done ) {
11106 var el = $( this ),
11107 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
11108 mode = $.effects.setMode( el, o.mode || "hide" ),
11109 show = mode === "show",
11110 hide = mode === "hide",
11111 size = o.size || 15,
11112 percent = /([0-9]+)%/.exec( size ),
11113 horizFirst = !!o.horizFirst,
11114 widthFirst = show !== horizFirst,
11115 ref = widthFirst ? [ "width", "height" ] : [ "height", "width" ],
11116 duration = o.duration / 2,
11121 $.effects.save( el, props );
11125 wrapper = $.effects.createWrapper( el ).css({
11128 distance = widthFirst ?
11129 [ wrapper.width(), wrapper.height() ] :
11130 [ wrapper.height(), wrapper.width() ];
11133 size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
11136 wrapper.css( horizFirst ? {
11146 animation1[ ref[ 0 ] ] = show ? distance[ 0 ] : size;
11147 animation2[ ref[ 1 ] ] = show ? distance[ 1 ] : 0;
11151 .animate( animation1, duration, o.easing )
11152 .animate( animation2, duration, o.easing, function() {
11156 $.effects.restore( el, props );
11157 $.effects.removeWrapper( el );
11165 * jQuery UI Effects Highlight 1.11.3
11166 * http://jqueryui.com
11168 * Copyright jQuery Foundation and other contributors
11169 * Released under the MIT license.
11170 * http://jquery.org/license
11172 * http://api.jqueryui.com/highlight-effect/
11176 var effectHighlight = $.effects.effect.highlight = function( o, done ) {
11177 var elem = $( this ),
11178 props = [ "backgroundImage", "backgroundColor", "opacity" ],
11179 mode = $.effects.setMode( elem, o.mode || "show" ),
11181 backgroundColor: elem.css( "backgroundColor" )
11184 if (mode === "hide") {
11185 animation.opacity = 0;
11188 $.effects.save( elem, props );
11193 backgroundImage: "none",
11194 backgroundColor: o.color || "#ffff99"
11196 .animate( animation, {
11198 duration: o.duration,
11200 complete: function() {
11201 if ( mode === "hide" ) {
11204 $.effects.restore( elem, props );
11212 * jQuery UI Effects Size 1.11.3
11213 * http://jqueryui.com
11215 * Copyright jQuery Foundation and other contributors
11216 * Released under the MIT license.
11217 * http://jquery.org/license
11219 * http://api.jqueryui.com/size-effect/
11223 var effectSize = $.effects.effect.size = function( o, done ) {
11226 var original, baseline, factor,
11228 props0 = [ "position", "top", "bottom", "left", "right", "width", "height", "overflow", "opacity" ],
11231 props1 = [ "position", "top", "bottom", "left", "right", "overflow", "opacity" ],
11233 // Copy for children
11234 props2 = [ "width", "height", "overflow" ],
11235 cProps = [ "fontSize" ],
11236 vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
11237 hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],
11240 mode = $.effects.setMode( el, o.mode || "effect" ),
11241 restore = o.restore || mode !== "effect",
11242 scale = o.scale || "both",
11243 origin = o.origin || [ "middle", "center" ],
11244 position = el.css( "position" ),
11245 props = restore ? props0 : props1,
11253 if ( mode === "show" ) {
11257 height: el.height(),
11259 outerHeight: el.outerHeight(),
11260 outerWidth: el.outerWidth()
11263 if ( o.mode === "toggle" && mode === "show" ) {
11264 el.from = o.to || zero;
11265 el.to = o.from || original;
11267 el.from = o.from || ( mode === "show" ? zero : original );
11268 el.to = o.to || ( mode === "hide" ? zero : original );
11271 // Set scaling factor
11274 y: el.from.height / original.height,
11275 x: el.from.width / original.width
11278 y: el.to.height / original.height,
11279 x: el.to.width / original.width
11283 // Scale the css box
11284 if ( scale === "box" || scale === "both" ) {
11286 // Vertical props scaling
11287 if ( factor.from.y !== factor.to.y ) {
11288 props = props.concat( vProps );
11289 el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from );
11290 el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to );
11293 // Horizontal props scaling
11294 if ( factor.from.x !== factor.to.x ) {
11295 props = props.concat( hProps );
11296 el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from );
11297 el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to );
11301 // Scale the content
11302 if ( scale === "content" || scale === "both" ) {
11304 // Vertical props scaling
11305 if ( factor.from.y !== factor.to.y ) {
11306 props = props.concat( cProps ).concat( props2 );
11307 el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from );
11308 el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to );
11312 $.effects.save( el, props );
11314 $.effects.createWrapper( el );
11315 el.css( "overflow", "hidden" ).css( el.from );
11318 if (origin) { // Calculate baseline shifts
11319 baseline = $.effects.getBaseline( origin, original );
11320 el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y;
11321 el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x;
11322 el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y;
11323 el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x;
11325 el.css( el.from ); // set top & left
11328 if ( scale === "content" || scale === "both" ) { // Scale the children
11330 // Add margins/font-size
11331 vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat(cProps);
11332 hProps = hProps.concat([ "marginLeft", "marginRight" ]);
11333 props2 = props0.concat(vProps).concat(hProps);
11335 el.find( "*[width]" ).each( function() {
11336 var child = $( this ),
11338 height: child.height(),
11339 width: child.width(),
11340 outerHeight: child.outerHeight(),
11341 outerWidth: child.outerWidth()
11344 $.effects.save(child, props2);
11348 height: c_original.height * factor.from.y,
11349 width: c_original.width * factor.from.x,
11350 outerHeight: c_original.outerHeight * factor.from.y,
11351 outerWidth: c_original.outerWidth * factor.from.x
11354 height: c_original.height * factor.to.y,
11355 width: c_original.width * factor.to.x,
11356 outerHeight: c_original.height * factor.to.y,
11357 outerWidth: c_original.width * factor.to.x
11360 // Vertical props scaling
11361 if ( factor.from.y !== factor.to.y ) {
11362 child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from );
11363 child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to );
11366 // Horizontal props scaling
11367 if ( factor.from.x !== factor.to.x ) {
11368 child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from );
11369 child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to );
11372 // Animate children
11373 child.css( child.from );
11374 child.animate( child.to, o.duration, o.easing, function() {
11376 // Restore children
11378 $.effects.restore( child, props2 );
11385 el.animate( el.to, {
11387 duration: o.duration,
11389 complete: function() {
11390 if ( el.to.opacity === 0 ) {
11391 el.css( "opacity", el.from.opacity );
11393 if ( mode === "hide" ) {
11396 $.effects.restore( el, props );
11399 // we need to calculate our new positioning based on the scaling
11400 if ( position === "static" ) {
11402 position: "relative",
11407 $.each([ "top", "left" ], function( idx, pos ) {
11408 el.css( pos, function( _, str ) {
11409 var val = parseInt( str, 10 ),
11410 toRef = idx ? el.to.left : el.to.top;
11412 // if original was "auto", recalculate the new value from wrapper
11413 if ( str === "auto" ) {
11414 return toRef + "px";
11417 return val + toRef + "px";
11423 $.effects.removeWrapper( el );
11432 * jQuery UI Effects Scale 1.11.3
11433 * http://jqueryui.com
11435 * Copyright jQuery Foundation and other contributors
11436 * Released under the MIT license.
11437 * http://jquery.org/license
11439 * http://api.jqueryui.com/scale-effect/
11443 var effectScale = $.effects.effect.scale = function( o, done ) {
11446 var el = $( this ),
11447 options = $.extend( true, {}, o ),
11448 mode = $.effects.setMode( el, o.mode || "effect" ),
11449 percent = parseInt( o.percent, 10 ) ||
11450 ( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === "hide" ? 0 : 100 ) ),
11451 direction = o.direction || "both",
11454 height: el.height(),
11456 outerHeight: el.outerHeight(),
11457 outerWidth: el.outerWidth()
11460 y: direction !== "horizontal" ? (percent / 100) : 1,
11461 x: direction !== "vertical" ? (percent / 100) : 1
11464 // We are going to pass this effect to the size effect:
11465 options.effect = "size";
11466 options.queue = false;
11467 options.complete = done;
11469 // Set default origin and restore for show/hide
11470 if ( mode !== "effect" ) {
11471 options.origin = origin || [ "middle", "center" ];
11472 options.restore = true;
11475 options.from = o.from || ( mode === "show" ? {
11482 height: original.height * factor.y,
11483 width: original.width * factor.x,
11484 outerHeight: original.outerHeight * factor.y,
11485 outerWidth: original.outerWidth * factor.x
11488 // Fade option to support puff
11489 if ( options.fade ) {
11490 if ( mode === "show" ) {
11491 options.from.opacity = 0;
11492 options.to.opacity = 1;
11494 if ( mode === "hide" ) {
11495 options.from.opacity = 1;
11496 options.to.opacity = 0;
11501 el.effect( options );
11507 * jQuery UI Effects Puff 1.11.3
11508 * http://jqueryui.com
11510 * Copyright jQuery Foundation and other contributors
11511 * Released under the MIT license.
11512 * http://jquery.org/license
11514 * http://api.jqueryui.com/puff-effect/
11518 var effectPuff = $.effects.effect.puff = function( o, done ) {
11519 var elem = $( this ),
11520 mode = $.effects.setMode( elem, o.mode || "hide" ),
11521 hide = mode === "hide",
11522 percent = parseInt( o.percent, 10 ) || 150,
11523 factor = percent / 100,
11525 height: elem.height(),
11526 width: elem.width(),
11527 outerHeight: elem.outerHeight(),
11528 outerWidth: elem.outerWidth()
11537 percent: hide ? percent : 100,
11541 height: original.height * factor,
11542 width: original.width * factor,
11543 outerHeight: original.outerHeight * factor,
11544 outerWidth: original.outerWidth * factor
11553 * jQuery UI Effects Pulsate 1.11.3
11554 * http://jqueryui.com
11556 * Copyright jQuery Foundation and other contributors
11557 * Released under the MIT license.
11558 * http://jquery.org/license
11560 * http://api.jqueryui.com/pulsate-effect/
11564 var effectPulsate = $.effects.effect.pulsate = function( o, done ) {
11565 var elem = $( this ),
11566 mode = $.effects.setMode( elem, o.mode || "show" ),
11567 show = mode === "show",
11568 hide = mode === "hide",
11569 showhide = ( show || mode === "hide" ),
11571 // showing or hiding leaves of the "last" animation
11572 anims = ( ( o.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
11573 duration = o.duration / anims,
11575 queue = elem.queue(),
11576 queuelen = queue.length,
11579 if ( show || !elem.is(":visible")) {
11580 elem.css( "opacity", 0 ).show();
11584 // anims - 1 opacity "toggles"
11585 for ( i = 1; i < anims; i++ ) {
11588 }, duration, o.easing );
11589 animateTo = 1 - animateTo;
11594 }, duration, o.easing);
11596 elem.queue(function() {
11603 // We just queued up "anims" animations, we need to put them next in the queue
11604 if ( queuelen > 1 ) {
11605 queue.splice.apply( queue,
11606 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
11613 * jQuery UI Effects Shake 1.11.3
11614 * http://jqueryui.com
11616 * Copyright jQuery Foundation and other contributors
11617 * Released under the MIT license.
11618 * http://jquery.org/license
11620 * http://api.jqueryui.com/shake-effect/
11624 var effectShake = $.effects.effect.shake = function( o, done ) {
11626 var el = $( this ),
11627 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
11628 mode = $.effects.setMode( el, o.mode || "effect" ),
11629 direction = o.direction || "left",
11630 distance = o.distance || 20,
11631 times = o.times || 3,
11632 anims = times * 2 + 1,
11633 speed = Math.round( o.duration / anims ),
11634 ref = (direction === "up" || direction === "down") ? "top" : "left",
11635 positiveMotion = (direction === "up" || direction === "left"),
11641 // we will need to re-assemble the queue to stack our animations in place
11642 queue = el.queue(),
11643 queuelen = queue.length;
11645 $.effects.save( el, props );
11647 $.effects.createWrapper( el );
11650 animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
11651 animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
11652 animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;
11655 el.animate( animation, speed, o.easing );
11658 for ( i = 1; i < times; i++ ) {
11659 el.animate( animation1, speed, o.easing ).animate( animation2, speed, o.easing );
11662 .animate( animation1, speed, o.easing )
11663 .animate( animation, speed / 2, o.easing )
11664 .queue(function() {
11665 if ( mode === "hide" ) {
11668 $.effects.restore( el, props );
11669 $.effects.removeWrapper( el );
11673 // inject all the animations we just queued to be first in line (after "inprogress")
11674 if ( queuelen > 1) {
11675 queue.splice.apply( queue,
11676 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
11684 * jQuery UI Effects Slide 1.11.3
11685 * http://jqueryui.com
11687 * Copyright jQuery Foundation and other contributors
11688 * Released under the MIT license.
11689 * http://jquery.org/license
11691 * http://api.jqueryui.com/slide-effect/
11695 var effectSlide = $.effects.effect.slide = function( o, done ) {
11698 var el = $( this ),
11699 props = [ "position", "top", "bottom", "left", "right", "width", "height" ],
11700 mode = $.effects.setMode( el, o.mode || "show" ),
11701 show = mode === "show",
11702 direction = o.direction || "left",
11703 ref = (direction === "up" || direction === "down") ? "top" : "left",
11704 positiveMotion = (direction === "up" || direction === "left"),
11709 $.effects.save( el, props );
11711 distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true );
11713 $.effects.createWrapper( el ).css({
11718 el.css( ref, positiveMotion ? (isNaN(distance) ? "-" + distance : -distance) : distance );
11722 animation[ ref ] = ( show ?
11723 ( positiveMotion ? "+=" : "-=") :
11724 ( positiveMotion ? "-=" : "+=")) +
11728 el.animate( animation, {
11730 duration: o.duration,
11732 complete: function() {
11733 if ( mode === "hide" ) {
11736 $.effects.restore( el, props );
11737 $.effects.removeWrapper( el );
11745 * jQuery UI Effects Transfer 1.11.3
11746 * http://jqueryui.com
11748 * Copyright jQuery Foundation and other contributors
11749 * Released under the MIT license.
11750 * http://jquery.org/license
11752 * http://api.jqueryui.com/transfer-effect/
11756 var effectTransfer = $.effects.effect.transfer = function( o, done ) {
11757 var elem = $( this ),
11758 target = $( o.to ),
11759 targetFixed = target.css( "position" ) === "fixed",
11761 fixTop = targetFixed ? body.scrollTop() : 0,
11762 fixLeft = targetFixed ? body.scrollLeft() : 0,
11763 endPosition = target.offset(),
11765 top: endPosition.top - fixTop,
11766 left: endPosition.left - fixLeft,
11767 height: target.innerHeight(),
11768 width: target.innerWidth()
11770 startPosition = elem.offset(),
11771 transfer = $( "<div class='ui-effects-transfer'></div>" )
11772 .appendTo( document.body )
11773 .addClass( o.className )
11775 top: startPosition.top - fixTop,
11776 left: startPosition.left - fixLeft,
11777 height: elem.innerHeight(),
11778 width: elem.innerWidth(),
11779 position: targetFixed ? "fixed" : "absolute"
11781 .animate( animation, o.duration, o.easing, function() {
11789 * jQuery UI Progressbar 1.11.3
11790 * http://jqueryui.com
11792 * Copyright jQuery Foundation and other contributors
11793 * Released under the MIT license.
11794 * http://jquery.org/license
11796 * http://api.jqueryui.com/progressbar/
11800 var progressbar = $.widget( "ui.progressbar", {
11812 _create: function() {
11813 // Constrain initial value
11814 this.oldValue = this.options.value = this._constrainedValue();
11817 .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
11819 // Only set static values, aria-valuenow and aria-valuemax are
11820 // set inside _refreshValue()
11821 role: "progressbar",
11822 "aria-valuemin": this.min
11825 this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" )
11826 .appendTo( this.element );
11828 this._refreshValue();
11831 _destroy: function() {
11833 .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
11834 .removeAttr( "role" )
11835 .removeAttr( "aria-valuemin" )
11836 .removeAttr( "aria-valuemax" )
11837 .removeAttr( "aria-valuenow" );
11839 this.valueDiv.remove();
11842 value: function( newValue ) {
11843 if ( newValue === undefined ) {
11844 return this.options.value;
11847 this.options.value = this._constrainedValue( newValue );
11848 this._refreshValue();
11851 _constrainedValue: function( newValue ) {
11852 if ( newValue === undefined ) {
11853 newValue = this.options.value;
11856 this.indeterminate = newValue === false;
11859 if ( typeof newValue !== "number" ) {
11863 return this.indeterminate ? false :
11864 Math.min( this.options.max, Math.max( this.min, newValue ) );
11867 _setOptions: function( options ) {
11868 // Ensure "value" option is set after other values (like max)
11869 var value = options.value;
11870 delete options.value;
11872 this._super( options );
11874 this.options.value = this._constrainedValue( value );
11875 this._refreshValue();
11878 _setOption: function( key, value ) {
11879 if ( key === "max" ) {
11880 // Don't allow a max less than min
11881 value = Math.max( this.min, value );
11883 if ( key === "disabled" ) {
11885 .toggleClass( "ui-state-disabled", !!value )
11886 .attr( "aria-disabled", value );
11888 this._super( key, value );
11891 _percentage: function() {
11892 return this.indeterminate ? 100 : 100 * ( this.options.value - this.min ) / ( this.options.max - this.min );
11895 _refreshValue: function() {
11896 var value = this.options.value,
11897 percentage = this._percentage();
11900 .toggle( this.indeterminate || value > this.min )
11901 .toggleClass( "ui-corner-right", value === this.options.max )
11902 .width( percentage.toFixed(0) + "%" );
11904 this.element.toggleClass( "ui-progressbar-indeterminate", this.indeterminate );
11906 if ( this.indeterminate ) {
11907 this.element.removeAttr( "aria-valuenow" );
11908 if ( !this.overlayDiv ) {
11909 this.overlayDiv = $( "<div class='ui-progressbar-overlay'></div>" ).appendTo( this.valueDiv );
11912 this.element.attr({
11913 "aria-valuemax": this.options.max,
11914 "aria-valuenow": value
11916 if ( this.overlayDiv ) {
11917 this.overlayDiv.remove();
11918 this.overlayDiv = null;
11922 if ( this.oldValue !== value ) {
11923 this.oldValue = value;
11924 this._trigger( "change" );
11926 if ( value === this.options.max ) {
11927 this._trigger( "complete" );
11934 * jQuery UI Selectable 1.11.3
11935 * http://jqueryui.com
11937 * Copyright jQuery Foundation and other contributors
11938 * Released under the MIT license.
11939 * http://jquery.org/license
11941 * http://api.jqueryui.com/selectable/
11945 var selectable = $.widget("ui.selectable", $.ui.mouse, {
11952 tolerance: "touch",
11962 _create: function() {
11966 this.element.addClass("ui-selectable");
11968 this.dragged = false;
11970 // cache selectee children based on filter
11971 this.refresh = function() {
11972 selectees = $(that.options.filter, that.element[0]);
11973 selectees.addClass("ui-selectee");
11974 selectees.each(function() {
11975 var $this = $(this),
11976 pos = $this.offset();
11977 $.data(this, "selectable-item", {
11982 right: pos.left + $this.outerWidth(),
11983 bottom: pos.top + $this.outerHeight(),
11984 startselected: false,
11985 selected: $this.hasClass("ui-selected"),
11986 selecting: $this.hasClass("ui-selecting"),
11987 unselecting: $this.hasClass("ui-unselecting")
11993 this.selectees = selectees.addClass("ui-selectee");
11997 this.helper = $("<div class='ui-selectable-helper'></div>");
12000 _destroy: function() {
12002 .removeClass("ui-selectee")
12003 .removeData("selectable-item");
12005 .removeClass("ui-selectable ui-selectable-disabled");
12006 this._mouseDestroy();
12009 _mouseStart: function(event) {
12011 options = this.options;
12013 this.opos = [ event.pageX, event.pageY ];
12015 if (this.options.disabled) {
12019 this.selectees = $(options.filter, this.element[0]);
12021 this._trigger("start", event);
12023 $(options.appendTo).append(this.helper);
12024 // position helper (lasso)
12026 "left": event.pageX,
12027 "top": event.pageY,
12032 if (options.autoRefresh) {
12036 this.selectees.filter(".ui-selected").each(function() {
12037 var selectee = $.data(this, "selectable-item");
12038 selectee.startselected = true;
12039 if (!event.metaKey && !event.ctrlKey) {
12040 selectee.$element.removeClass("ui-selected");
12041 selectee.selected = false;
12042 selectee.$element.addClass("ui-unselecting");
12043 selectee.unselecting = true;
12044 // selectable UNSELECTING callback
12045 that._trigger("unselecting", event, {
12046 unselecting: selectee.element
12051 $(event.target).parents().addBack().each(function() {
12053 selectee = $.data(this, "selectable-item");
12055 doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass("ui-selected");
12057 .removeClass(doSelect ? "ui-unselecting" : "ui-selected")
12058 .addClass(doSelect ? "ui-selecting" : "ui-unselecting");
12059 selectee.unselecting = !doSelect;
12060 selectee.selecting = doSelect;
12061 selectee.selected = doSelect;
12062 // selectable (UN)SELECTING callback
12064 that._trigger("selecting", event, {
12065 selecting: selectee.element
12068 that._trigger("unselecting", event, {
12069 unselecting: selectee.element
12078 _mouseDrag: function(event) {
12080 this.dragged = true;
12082 if (this.options.disabled) {
12088 options = this.options,
12094 if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; }
12095 if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; }
12096 this.helper.css({ left: x1, top: y1, width: x2 - x1, height: y2 - y1 });
12098 this.selectees.each(function() {
12099 var selectee = $.data(this, "selectable-item"),
12102 //prevent helper from being selected if appendTo: selectable
12103 if (!selectee || selectee.element === that.element[0]) {
12107 if (options.tolerance === "touch") {
12108 hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) );
12109 } else if (options.tolerance === "fit") {
12110 hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2);
12115 if (selectee.selected) {
12116 selectee.$element.removeClass("ui-selected");
12117 selectee.selected = false;
12119 if (selectee.unselecting) {
12120 selectee.$element.removeClass("ui-unselecting");
12121 selectee.unselecting = false;
12123 if (!selectee.selecting) {
12124 selectee.$element.addClass("ui-selecting");
12125 selectee.selecting = true;
12126 // selectable SELECTING callback
12127 that._trigger("selecting", event, {
12128 selecting: selectee.element
12133 if (selectee.selecting) {
12134 if ((event.metaKey || event.ctrlKey) && selectee.startselected) {
12135 selectee.$element.removeClass("ui-selecting");
12136 selectee.selecting = false;
12137 selectee.$element.addClass("ui-selected");
12138 selectee.selected = true;
12140 selectee.$element.removeClass("ui-selecting");
12141 selectee.selecting = false;
12142 if (selectee.startselected) {
12143 selectee.$element.addClass("ui-unselecting");
12144 selectee.unselecting = true;
12146 // selectable UNSELECTING callback
12147 that._trigger("unselecting", event, {
12148 unselecting: selectee.element
12152 if (selectee.selected) {
12153 if (!event.metaKey && !event.ctrlKey && !selectee.startselected) {
12154 selectee.$element.removeClass("ui-selected");
12155 selectee.selected = false;
12157 selectee.$element.addClass("ui-unselecting");
12158 selectee.unselecting = true;
12159 // selectable UNSELECTING callback
12160 that._trigger("unselecting", event, {
12161 unselecting: selectee.element
12171 _mouseStop: function(event) {
12174 this.dragged = false;
12176 $(".ui-unselecting", this.element[0]).each(function() {
12177 var selectee = $.data(this, "selectable-item");
12178 selectee.$element.removeClass("ui-unselecting");
12179 selectee.unselecting = false;
12180 selectee.startselected = false;
12181 that._trigger("unselected", event, {
12182 unselected: selectee.element
12185 $(".ui-selecting", this.element[0]).each(function() {
12186 var selectee = $.data(this, "selectable-item");
12187 selectee.$element.removeClass("ui-selecting").addClass("ui-selected");
12188 selectee.selecting = false;
12189 selectee.selected = true;
12190 selectee.startselected = true;
12191 that._trigger("selected", event, {
12192 selected: selectee.element
12195 this._trigger("stop", event);
12197 this.helper.remove();
12206 * jQuery UI Selectmenu 1.11.3
12207 * http://jqueryui.com
12209 * Copyright jQuery Foundation and other contributors
12210 * Released under the MIT license.
12211 * http://jquery.org/license
12213 * http://api.jqueryui.com/selectmenu
12217 var selectmenu = $.widget( "ui.selectmenu", {
12219 defaultElement: "<select>",
12224 button: "ui-icon-triangle-1-s"
12241 _create: function() {
12242 var selectmenuId = this.element.uniqueId().attr( "id" );
12244 element: selectmenuId,
12245 button: selectmenuId + "-button",
12246 menu: selectmenuId + "-menu"
12249 this._drawButton();
12252 if ( this.options.disabled ) {
12257 _drawButton: function() {
12260 // Associate existing label with the new button
12261 this.label = $( "label[for='" + this.ids.element + "']" ).attr( "for", this.ids.button );
12262 this._on( this.label, {
12263 click: function( event ) {
12264 this.button.focus();
12265 event.preventDefault();
12269 // Hide original select element
12270 this.element.hide();
12273 this.button = $( "<span>", {
12274 "class": "ui-selectmenu-button ui-widget ui-state-default ui-corner-all",
12275 tabindex: this.options.disabled ? -1 : 0,
12276 id: this.ids.button,
12278 "aria-expanded": "false",
12279 "aria-autocomplete": "list",
12280 "aria-owns": this.ids.menu,
12281 "aria-haspopup": "true"
12283 .insertAfter( this.element );
12286 "class": "ui-icon " + this.options.icons.button
12288 .prependTo( this.button );
12290 this.buttonText = $( "<span>", {
12291 "class": "ui-selectmenu-text"
12293 .appendTo( this.button );
12295 this._setText( this.buttonText, this.element.find( "option:selected" ).text() );
12296 this._resizeButton();
12298 this._on( this.button, this._buttonEvents );
12299 this.button.one( "focusin", function() {
12301 // Delay rendering the menu items until the button receives focus.
12302 // The menu may have already been rendered via a programmatic open.
12303 if ( !that.menuItems ) {
12304 that._refreshMenu();
12307 this._hoverable( this.button );
12308 this._focusable( this.button );
12311 _drawMenu: function() {
12315 this.menu = $( "<ul>", {
12316 "aria-hidden": "true",
12317 "aria-labelledby": this.ids.button,
12322 this.menuWrap = $( "<div>", {
12323 "class": "ui-selectmenu-menu ui-front"
12325 .append( this.menu )
12326 .appendTo( this._appendTo() );
12328 // Initialize menu widget
12329 this.menuInstance = this.menu
12332 select: function( event, ui ) {
12333 event.preventDefault();
12336 // If the item was selected via a click, the text selection
12337 // will be destroyed in IE
12338 that._setSelection();
12340 that._select( ui.item.data( "ui-selectmenu-item" ), event );
12342 focus: function( event, ui ) {
12343 var item = ui.item.data( "ui-selectmenu-item" );
12345 // Prevent inital focus from firing and check if its a newly focused item
12346 if ( that.focusIndex != null && item.index !== that.focusIndex ) {
12347 that._trigger( "focus", event, { item: item } );
12348 if ( !that.isOpen ) {
12349 that._select( item, event );
12352 that.focusIndex = item.index;
12354 that.button.attr( "aria-activedescendant",
12355 that.menuItems.eq( item.index ).attr( "id" ) );
12358 .menu( "instance" );
12360 // Adjust menu styles to dropdown
12362 .addClass( "ui-corner-bottom" )
12363 .removeClass( "ui-corner-all" );
12365 // Don't close the menu on mouseleave
12366 this.menuInstance._off( this.menu, "mouseleave" );
12368 // Cancel the menu's collapseAll on document click
12369 this.menuInstance._closeOnDocumentClick = function() {
12373 // Selects often contain empty items, but never contain dividers
12374 this.menuInstance._isDivider = function() {
12379 refresh: function() {
12380 this._refreshMenu();
12381 this._setText( this.buttonText, this._getSelectedItem().text() );
12382 if ( !this.options.width ) {
12383 this._resizeButton();
12387 _refreshMenu: function() {
12391 options = this.element.find( "option" );
12393 if ( !options.length ) {
12397 this._parseOptions( options );
12398 this._renderMenu( this.menu, this.items );
12400 this.menuInstance.refresh();
12401 this.menuItems = this.menu.find( "li" ).not( ".ui-selectmenu-optgroup" );
12403 item = this._getSelectedItem();
12405 // Update the menu to have the correct item focused
12406 this.menuInstance.focus( null, item );
12407 this._setAria( item.data( "ui-selectmenu-item" ) );
12409 // Set disabled state
12410 this._setOption( "disabled", this.element.prop( "disabled" ) );
12413 open: function( event ) {
12414 if ( this.options.disabled ) {
12418 // If this is the first time the menu is being opened, render the items
12419 if ( !this.menuItems ) {
12420 this._refreshMenu();
12423 // Menu clears focus on close, reset focus to selected item
12424 this.menu.find( ".ui-state-focus" ).removeClass( "ui-state-focus" );
12425 this.menuInstance.focus( null, this._getSelectedItem() );
12428 this.isOpen = true;
12429 this._toggleAttr();
12430 this._resizeMenu();
12433 this._on( this.document, this._documentClick );
12435 this._trigger( "open", event );
12438 _position: function() {
12439 this.menuWrap.position( $.extend( { of: this.button }, this.options.position ) );
12442 close: function( event ) {
12443 if ( !this.isOpen ) {
12447 this.isOpen = false;
12448 this._toggleAttr();
12451 this._off( this.document );
12453 this._trigger( "close", event );
12456 widget: function() {
12457 return this.button;
12460 menuWidget: function() {
12464 _renderMenu: function( ul, items ) {
12466 currentOptgroup = "";
12468 $.each( items, function( index, item ) {
12469 if ( item.optgroup !== currentOptgroup ) {
12471 "class": "ui-selectmenu-optgroup ui-menu-divider" +
12472 ( item.element.parent( "optgroup" ).prop( "disabled" ) ?
12473 " ui-state-disabled" :
12475 text: item.optgroup
12479 currentOptgroup = item.optgroup;
12482 that._renderItemData( ul, item );
12486 _renderItemData: function( ul, item ) {
12487 return this._renderItem( ul, item ).data( "ui-selectmenu-item", item );
12490 _renderItem: function( ul, item ) {
12491 var li = $( "<li>" );
12493 if ( item.disabled ) {
12494 li.addClass( "ui-state-disabled" );
12496 this._setText( li, item.label );
12498 return li.appendTo( ul );
12501 _setText: function( element, value ) {
12503 element.text( value );
12505 element.html( " " );
12509 _move: function( direction, event ) {
12511 filter = ".ui-menu-item";
12513 if ( this.isOpen ) {
12514 item = this.menuItems.eq( this.focusIndex );
12516 item = this.menuItems.eq( this.element[ 0 ].selectedIndex );
12517 filter += ":not(.ui-state-disabled)";
12520 if ( direction === "first" || direction === "last" ) {
12521 next = item[ direction === "first" ? "prevAll" : "nextAll" ]( filter ).eq( -1 );
12523 next = item[ direction + "All" ]( filter ).eq( 0 );
12526 if ( next.length ) {
12527 this.menuInstance.focus( event, next );
12531 _getSelectedItem: function() {
12532 return this.menuItems.eq( this.element[ 0 ].selectedIndex );
12535 _toggle: function( event ) {
12536 this[ this.isOpen ? "close" : "open" ]( event );
12539 _setSelection: function() {
12542 if ( !this.range ) {
12546 if ( window.getSelection ) {
12547 selection = window.getSelection();
12548 selection.removeAllRanges();
12549 selection.addRange( this.range );
12553 this.range.select();
12557 // Setting the text selection kills the button focus in IE, but
12558 // restoring the focus doesn't kill the selection.
12559 this.button.focus();
12563 mousedown: function( event ) {
12564 if ( !this.isOpen ) {
12568 if ( !$( event.target ).closest( ".ui-selectmenu-menu, #" + this.ids.button ).length ) {
12569 this.close( event );
12576 // Prevent text selection from being reset when interacting with the selectmenu (#10144)
12577 mousedown: function() {
12580 if ( window.getSelection ) {
12581 selection = window.getSelection();
12582 if ( selection.rangeCount ) {
12583 this.range = selection.getRangeAt( 0 );
12588 this.range = document.selection.createRange();
12592 click: function( event ) {
12593 this._setSelection();
12594 this._toggle( event );
12597 keydown: function( event ) {
12598 var preventDefault = true;
12599 switch ( event.keyCode ) {
12600 case $.ui.keyCode.TAB:
12601 case $.ui.keyCode.ESCAPE:
12602 this.close( event );
12603 preventDefault = false;
12605 case $.ui.keyCode.ENTER:
12606 if ( this.isOpen ) {
12607 this._selectFocusedItem( event );
12610 case $.ui.keyCode.UP:
12611 if ( event.altKey ) {
12612 this._toggle( event );
12614 this._move( "prev", event );
12617 case $.ui.keyCode.DOWN:
12618 if ( event.altKey ) {
12619 this._toggle( event );
12621 this._move( "next", event );
12624 case $.ui.keyCode.SPACE:
12625 if ( this.isOpen ) {
12626 this._selectFocusedItem( event );
12628 this._toggle( event );
12631 case $.ui.keyCode.LEFT:
12632 this._move( "prev", event );
12634 case $.ui.keyCode.RIGHT:
12635 this._move( "next", event );
12637 case $.ui.keyCode.HOME:
12638 case $.ui.keyCode.PAGE_UP:
12639 this._move( "first", event );
12641 case $.ui.keyCode.END:
12642 case $.ui.keyCode.PAGE_DOWN:
12643 this._move( "last", event );
12646 this.menu.trigger( event );
12647 preventDefault = false;
12650 if ( preventDefault ) {
12651 event.preventDefault();
12656 _selectFocusedItem: function( event ) {
12657 var item = this.menuItems.eq( this.focusIndex );
12658 if ( !item.hasClass( "ui-state-disabled" ) ) {
12659 this._select( item.data( "ui-selectmenu-item" ), event );
12663 _select: function( item, event ) {
12664 var oldIndex = this.element[ 0 ].selectedIndex;
12666 // Change native select element
12667 this.element[ 0 ].selectedIndex = item.index;
12668 this._setText( this.buttonText, item.label );
12669 this._setAria( item );
12670 this._trigger( "select", event, { item: item } );
12672 if ( item.index !== oldIndex ) {
12673 this._trigger( "change", event, { item: item } );
12676 this.close( event );
12679 _setAria: function( item ) {
12680 var id = this.menuItems.eq( item.index ).attr( "id" );
12683 "aria-labelledby": id,
12684 "aria-activedescendant": id
12686 this.menu.attr( "aria-activedescendant", id );
12689 _setOption: function( key, value ) {
12690 if ( key === "icons" ) {
12691 this.button.find( "span.ui-icon" )
12692 .removeClass( this.options.icons.button )
12693 .addClass( value.button );
12696 this._super( key, value );
12698 if ( key === "appendTo" ) {
12699 this.menuWrap.appendTo( this._appendTo() );
12702 if ( key === "disabled" ) {
12703 this.menuInstance.option( "disabled", value );
12705 .toggleClass( "ui-state-disabled", value )
12706 .attr( "aria-disabled", value );
12708 this.element.prop( "disabled", value );
12710 this.button.attr( "tabindex", -1 );
12713 this.button.attr( "tabindex", 0 );
12717 if ( key === "width" ) {
12718 this._resizeButton();
12722 _appendTo: function() {
12723 var element = this.options.appendTo;
12726 element = element.jquery || element.nodeType ?
12728 this.document.find( element ).eq( 0 );
12731 if ( !element || !element[ 0 ] ) {
12732 element = this.element.closest( ".ui-front" );
12735 if ( !element.length ) {
12736 element = this.document[ 0 ].body;
12742 _toggleAttr: function() {
12744 .toggleClass( "ui-corner-top", this.isOpen )
12745 .toggleClass( "ui-corner-all", !this.isOpen )
12746 .attr( "aria-expanded", this.isOpen );
12747 this.menuWrap.toggleClass( "ui-selectmenu-open", this.isOpen );
12748 this.menu.attr( "aria-hidden", !this.isOpen );
12751 _resizeButton: function() {
12752 var width = this.options.width;
12755 width = this.element.show().outerWidth();
12756 this.element.hide();
12759 this.button.outerWidth( width );
12762 _resizeMenu: function() {
12763 this.menu.outerWidth( Math.max(
12764 this.button.outerWidth(),
12767 // IE10 wraps long text (possibly a rounding bug)
12768 // so we add 1px to avoid the wrapping
12769 this.menu.width( "" ).outerWidth() + 1
12773 _getCreateOptions: function() {
12774 return { disabled: this.element.prop( "disabled" ) };
12777 _parseOptions: function( options ) {
12779 options.each(function( index, item ) {
12780 var option = $( item ),
12781 optgroup = option.parent( "optgroup" );
12785 value: option.val(),
12786 label: option.text(),
12787 optgroup: optgroup.attr( "label" ) || "",
12788 disabled: optgroup.prop( "disabled" ) || option.prop( "disabled" )
12794 _destroy: function() {
12795 this.menuWrap.remove();
12796 this.button.remove();
12797 this.element.show();
12798 this.element.removeUniqueId();
12799 this.label.attr( "for", this.ids.element );
12805 * jQuery UI Slider 1.11.3
12806 * http://jqueryui.com
12808 * Copyright jQuery Foundation and other contributors
12809 * Released under the MIT license.
12810 * http://jquery.org/license
12812 * http://api.jqueryui.com/slider/
12816 var slider = $.widget( "ui.slider", $.ui.mouse, {
12818 widgetEventPrefix: "slide",
12825 orientation: "horizontal",
12838 // number of pages in a slider
12839 // (how many times can you page up/down to go through the whole range)
12842 _create: function() {
12843 this._keySliding = false;
12844 this._mouseSliding = false;
12845 this._animateOff = true;
12846 this._handleIndex = null;
12847 this._detectOrientation();
12849 this._calculateNewMax();
12852 .addClass( "ui-slider" +
12853 " ui-slider-" + this.orientation +
12855 " ui-widget-content" +
12859 this._setOption( "disabled", this.options.disabled );
12861 this._animateOff = false;
12864 _refresh: function() {
12865 this._createRange();
12866 this._createHandles();
12867 this._setupEvents();
12868 this._refreshValue();
12871 _createHandles: function() {
12872 var i, handleCount,
12873 options = this.options,
12874 existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ),
12875 handle = "<span class='ui-slider-handle ui-state-default ui-corner-all' tabindex='0'></span>",
12878 handleCount = ( options.values && options.values.length ) || 1;
12880 if ( existingHandles.length > handleCount ) {
12881 existingHandles.slice( handleCount ).remove();
12882 existingHandles = existingHandles.slice( 0, handleCount );
12885 for ( i = existingHandles.length; i < handleCount; i++ ) {
12886 handles.push( handle );
12889 this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
12891 this.handle = this.handles.eq( 0 );
12893 this.handles.each(function( i ) {
12894 $( this ).data( "ui-slider-handle-index", i );
12898 _createRange: function() {
12899 var options = this.options,
12902 if ( options.range ) {
12903 if ( options.range === true ) {
12904 if ( !options.values ) {
12905 options.values = [ this._valueMin(), this._valueMin() ];
12906 } else if ( options.values.length && options.values.length !== 2 ) {
12907 options.values = [ options.values[0], options.values[0] ];
12908 } else if ( $.isArray( options.values ) ) {
12909 options.values = options.values.slice(0);
12913 if ( !this.range || !this.range.length ) {
12914 this.range = $( "<div></div>" )
12915 .appendTo( this.element );
12917 classes = "ui-slider-range" +
12918 // note: this isn't the most fittingly semantic framework class for this element,
12919 // but worked best visually with a variety of themes
12920 " ui-widget-header ui-corner-all";
12922 this.range.removeClass( "ui-slider-range-min ui-slider-range-max" )
12923 // Handle range switching from true to min/max
12930 this.range.addClass( classes +
12931 ( ( options.range === "min" || options.range === "max" ) ? " ui-slider-range-" + options.range : "" ) );
12933 if ( this.range ) {
12934 this.range.remove();
12940 _setupEvents: function() {
12941 this._off( this.handles );
12942 this._on( this.handles, this._handleEvents );
12943 this._hoverable( this.handles );
12944 this._focusable( this.handles );
12947 _destroy: function() {
12948 this.handles.remove();
12949 if ( this.range ) {
12950 this.range.remove();
12954 .removeClass( "ui-slider" +
12955 " ui-slider-horizontal" +
12956 " ui-slider-vertical" +
12958 " ui-widget-content" +
12959 " ui-corner-all" );
12961 this._mouseDestroy();
12964 _mouseCapture: function( event ) {
12965 var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
12969 if ( o.disabled ) {
12973 this.elementSize = {
12974 width: this.element.outerWidth(),
12975 height: this.element.outerHeight()
12977 this.elementOffset = this.element.offset();
12979 position = { x: event.pageX, y: event.pageY };
12980 normValue = this._normValueFromMouse( position );
12981 distance = this._valueMax() - this._valueMin() + 1;
12982 this.handles.each(function( i ) {
12983 var thisDistance = Math.abs( normValue - that.values(i) );
12984 if (( distance > thisDistance ) ||
12985 ( distance === thisDistance &&
12986 (i === that._lastChangedValue || that.values(i) === o.min ))) {
12987 distance = thisDistance;
12988 closestHandle = $( this );
12993 allowed = this._start( event, index );
12994 if ( allowed === false ) {
12997 this._mouseSliding = true;
12999 this._handleIndex = index;
13002 .addClass( "ui-state-active" )
13005 offset = closestHandle.offset();
13006 mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
13007 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
13008 left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
13009 top: event.pageY - offset.top -
13010 ( closestHandle.height() / 2 ) -
13011 ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) -
13012 ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) +
13013 ( parseInt( closestHandle.css("marginTop"), 10 ) || 0)
13016 if ( !this.handles.hasClass( "ui-state-hover" ) ) {
13017 this._slide( event, index, normValue );
13019 this._animateOff = true;
13023 _mouseStart: function() {
13027 _mouseDrag: function( event ) {
13028 var position = { x: event.pageX, y: event.pageY },
13029 normValue = this._normValueFromMouse( position );
13031 this._slide( event, this._handleIndex, normValue );
13036 _mouseStop: function( event ) {
13037 this.handles.removeClass( "ui-state-active" );
13038 this._mouseSliding = false;
13040 this._stop( event, this._handleIndex );
13041 this._change( event, this._handleIndex );
13043 this._handleIndex = null;
13044 this._clickOffset = null;
13045 this._animateOff = false;
13050 _detectOrientation: function() {
13051 this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
13054 _normValueFromMouse: function( position ) {
13061 if ( this.orientation === "horizontal" ) {
13062 pixelTotal = this.elementSize.width;
13063 pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
13065 pixelTotal = this.elementSize.height;
13066 pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );
13069 percentMouse = ( pixelMouse / pixelTotal );
13070 if ( percentMouse > 1 ) {
13073 if ( percentMouse < 0 ) {
13076 if ( this.orientation === "vertical" ) {
13077 percentMouse = 1 - percentMouse;
13080 valueTotal = this._valueMax() - this._valueMin();
13081 valueMouse = this._valueMin() + percentMouse * valueTotal;
13083 return this._trimAlignValue( valueMouse );
13086 _start: function( event, index ) {
13088 handle: this.handles[ index ],
13089 value: this.value()
13091 if ( this.options.values && this.options.values.length ) {
13092 uiHash.value = this.values( index );
13093 uiHash.values = this.values();
13095 return this._trigger( "start", event, uiHash );
13098 _slide: function( event, index, newVal ) {
13103 if ( this.options.values && this.options.values.length ) {
13104 otherVal = this.values( index ? 0 : 1 );
13106 if ( ( this.options.values.length === 2 && this.options.range === true ) &&
13107 ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )
13112 if ( newVal !== this.values( index ) ) {
13113 newValues = this.values();
13114 newValues[ index ] = newVal;
13115 // A slide can be canceled by returning false from the slide callback
13116 allowed = this._trigger( "slide", event, {
13117 handle: this.handles[ index ],
13121 otherVal = this.values( index ? 0 : 1 );
13122 if ( allowed !== false ) {
13123 this.values( index, newVal );
13127 if ( newVal !== this.value() ) {
13128 // A slide can be canceled by returning false from the slide callback
13129 allowed = this._trigger( "slide", event, {
13130 handle: this.handles[ index ],
13133 if ( allowed !== false ) {
13134 this.value( newVal );
13140 _stop: function( event, index ) {
13142 handle: this.handles[ index ],
13143 value: this.value()
13145 if ( this.options.values && this.options.values.length ) {
13146 uiHash.value = this.values( index );
13147 uiHash.values = this.values();
13150 this._trigger( "stop", event, uiHash );
13153 _change: function( event, index ) {
13154 if ( !this._keySliding && !this._mouseSliding ) {
13156 handle: this.handles[ index ],
13157 value: this.value()
13159 if ( this.options.values && this.options.values.length ) {
13160 uiHash.value = this.values( index );
13161 uiHash.values = this.values();
13164 //store the last changed value index for reference when handles overlap
13165 this._lastChangedValue = index;
13167 this._trigger( "change", event, uiHash );
13171 value: function( newValue ) {
13172 if ( arguments.length ) {
13173 this.options.value = this._trimAlignValue( newValue );
13174 this._refreshValue();
13175 this._change( null, 0 );
13179 return this._value();
13182 values: function( index, newValue ) {
13187 if ( arguments.length > 1 ) {
13188 this.options.values[ index ] = this._trimAlignValue( newValue );
13189 this._refreshValue();
13190 this._change( null, index );
13194 if ( arguments.length ) {
13195 if ( $.isArray( arguments[ 0 ] ) ) {
13196 vals = this.options.values;
13197 newValues = arguments[ 0 ];
13198 for ( i = 0; i < vals.length; i += 1 ) {
13199 vals[ i ] = this._trimAlignValue( newValues[ i ] );
13200 this._change( null, i );
13202 this._refreshValue();
13204 if ( this.options.values && this.options.values.length ) {
13205 return this._values( index );
13207 return this.value();
13211 return this._values();
13215 _setOption: function( key, value ) {
13219 if ( key === "range" && this.options.range === true ) {
13220 if ( value === "min" ) {
13221 this.options.value = this._values( 0 );
13222 this.options.values = null;
13223 } else if ( value === "max" ) {
13224 this.options.value = this._values( this.options.values.length - 1 );
13225 this.options.values = null;
13229 if ( $.isArray( this.options.values ) ) {
13230 valsLength = this.options.values.length;
13233 if ( key === "disabled" ) {
13234 this.element.toggleClass( "ui-state-disabled", !!value );
13237 this._super( key, value );
13240 case "orientation":
13241 this._detectOrientation();
13243 .removeClass( "ui-slider-horizontal ui-slider-vertical" )
13244 .addClass( "ui-slider-" + this.orientation );
13245 this._refreshValue();
13247 // Reset positioning from previous orientation
13248 this.handles.css( value === "horizontal" ? "bottom" : "left", "" );
13251 this._animateOff = true;
13252 this._refreshValue();
13253 this._change( null, 0 );
13254 this._animateOff = false;
13257 this._animateOff = true;
13258 this._refreshValue();
13259 for ( i = 0; i < valsLength; i += 1 ) {
13260 this._change( null, i );
13262 this._animateOff = false;
13267 this._animateOff = true;
13268 this._calculateNewMax();
13269 this._refreshValue();
13270 this._animateOff = false;
13273 this._animateOff = true;
13275 this._animateOff = false;
13280 //internal value getter
13281 // _value() returns value trimmed by min and max, aligned by step
13282 _value: function() {
13283 var val = this.options.value;
13284 val = this._trimAlignValue( val );
13289 //internal values getter
13290 // _values() returns array of values trimmed by min and max, aligned by step
13291 // _values( index ) returns single value trimmed by min and max, aligned by step
13292 _values: function( index ) {
13297 if ( arguments.length ) {
13298 val = this.options.values[ index ];
13299 val = this._trimAlignValue( val );
13302 } else if ( this.options.values && this.options.values.length ) {
13303 // .slice() creates a copy of the array
13304 // this copy gets trimmed by min and max and then returned
13305 vals = this.options.values.slice();
13306 for ( i = 0; i < vals.length; i += 1) {
13307 vals[ i ] = this._trimAlignValue( vals[ i ] );
13316 // returns the step-aligned value that val is closest to, between (inclusive) min and max
13317 _trimAlignValue: function( val ) {
13318 if ( val <= this._valueMin() ) {
13319 return this._valueMin();
13321 if ( val >= this._valueMax() ) {
13322 return this._valueMax();
13324 var step = ( this.options.step > 0 ) ? this.options.step : 1,
13325 valModStep = (val - this._valueMin()) % step,
13326 alignValue = val - valModStep;
13328 if ( Math.abs(valModStep) * 2 >= step ) {
13329 alignValue += ( valModStep > 0 ) ? step : ( -step );
13332 // Since JavaScript has problems with large floats, round
13333 // the final value to 5 digits after the decimal point (see #4124)
13334 return parseFloat( alignValue.toFixed(5) );
13337 _calculateNewMax: function() {
13338 var max = this.options.max,
13339 min = this._valueMin(),
13340 step = this.options.step,
13341 aboveMin = Math.floor( ( max - min ) / step ) * step;
13342 max = aboveMin + min;
13343 this.max = parseFloat( max.toFixed( this._precision() ) );
13346 _precision: function() {
13347 var precision = this._precisionOf( this.options.step );
13348 if ( this.options.min !== null ) {
13349 precision = Math.max( precision, this._precisionOf( this.options.min ) );
13354 _precisionOf: function( num ) {
13355 var str = num.toString(),
13356 decimal = str.indexOf( "." );
13357 return decimal === -1 ? 0 : str.length - decimal - 1;
13360 _valueMin: function() {
13361 return this.options.min;
13364 _valueMax: function() {
13368 _refreshValue: function() {
13369 var lastValPercent, valPercent, value, valueMin, valueMax,
13370 oRange = this.options.range,
13373 animate = ( !this._animateOff ) ? o.animate : false,
13376 if ( this.options.values && this.options.values.length ) {
13377 this.handles.each(function( i ) {
13378 valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100;
13379 _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
13380 $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
13381 if ( that.options.range === true ) {
13382 if ( that.orientation === "horizontal" ) {
13384 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate );
13387 that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
13391 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate );
13394 that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
13398 lastValPercent = valPercent;
13401 value = this.value();
13402 valueMin = this._valueMin();
13403 valueMax = this._valueMax();
13404 valPercent = ( valueMax !== valueMin ) ?
13405 ( value - valueMin ) / ( valueMax - valueMin ) * 100 :
13407 _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
13408 this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
13410 if ( oRange === "min" && this.orientation === "horizontal" ) {
13411 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate );
13413 if ( oRange === "max" && this.orientation === "horizontal" ) {
13414 this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
13416 if ( oRange === "min" && this.orientation === "vertical" ) {
13417 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate );
13419 if ( oRange === "max" && this.orientation === "vertical" ) {
13420 this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
13426 keydown: function( event ) {
13427 var allowed, curVal, newVal, step,
13428 index = $( event.target ).data( "ui-slider-handle-index" );
13430 switch ( event.keyCode ) {
13431 case $.ui.keyCode.HOME:
13432 case $.ui.keyCode.END:
13433 case $.ui.keyCode.PAGE_UP:
13434 case $.ui.keyCode.PAGE_DOWN:
13435 case $.ui.keyCode.UP:
13436 case $.ui.keyCode.RIGHT:
13437 case $.ui.keyCode.DOWN:
13438 case $.ui.keyCode.LEFT:
13439 event.preventDefault();
13440 if ( !this._keySliding ) {
13441 this._keySliding = true;
13442 $( event.target ).addClass( "ui-state-active" );
13443 allowed = this._start( event, index );
13444 if ( allowed === false ) {
13451 step = this.options.step;
13452 if ( this.options.values && this.options.values.length ) {
13453 curVal = newVal = this.values( index );
13455 curVal = newVal = this.value();
13458 switch ( event.keyCode ) {
13459 case $.ui.keyCode.HOME:
13460 newVal = this._valueMin();
13462 case $.ui.keyCode.END:
13463 newVal = this._valueMax();
13465 case $.ui.keyCode.PAGE_UP:
13466 newVal = this._trimAlignValue(
13467 curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages )
13470 case $.ui.keyCode.PAGE_DOWN:
13471 newVal = this._trimAlignValue(
13472 curVal - ( (this._valueMax() - this._valueMin()) / this.numPages ) );
13474 case $.ui.keyCode.UP:
13475 case $.ui.keyCode.RIGHT:
13476 if ( curVal === this._valueMax() ) {
13479 newVal = this._trimAlignValue( curVal + step );
13481 case $.ui.keyCode.DOWN:
13482 case $.ui.keyCode.LEFT:
13483 if ( curVal === this._valueMin() ) {
13486 newVal = this._trimAlignValue( curVal - step );
13490 this._slide( event, index, newVal );
13492 keyup: function( event ) {
13493 var index = $( event.target ).data( "ui-slider-handle-index" );
13495 if ( this._keySliding ) {
13496 this._keySliding = false;
13497 this._stop( event, index );
13498 this._change( event, index );
13499 $( event.target ).removeClass( "ui-state-active" );
13507 * jQuery UI Sortable 1.11.3
13508 * http://jqueryui.com
13510 * Copyright jQuery Foundation and other contributors
13511 * Released under the MIT license.
13512 * http://jquery.org/license
13514 * http://api.jqueryui.com/sortable/
13518 var sortable = $.widget("ui.sortable", $.ui.mouse, {
13520 widgetEventPrefix: "sort",
13523 appendTo: "parent",
13525 connectWith: false,
13526 containment: false,
13530 forcePlaceholderSize: false,
13531 forceHelperSize: false,
13534 helper: "original",
13537 placeholder: false,
13540 scrollSensitivity: 20,
13543 tolerance: "intersect",
13561 _isOverAxis: function( x, reference, size ) {
13562 return ( x >= reference ) && ( x < ( reference + size ) );
13565 _isFloating: function( item ) {
13566 return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display"));
13569 _create: function() {
13571 var o = this.options;
13572 this.containerCache = {};
13573 this.element.addClass("ui-sortable");
13578 //Let's determine if the items are being displayed horizontally
13579 this.floating = this.items.length ? o.axis === "x" || this._isFloating(this.items[0].item) : false;
13581 //Let's determine the parent's offset
13582 this.offset = this.element.offset();
13584 //Initialize mouse events for interaction
13587 this._setHandleClassName();
13589 //We're ready to go
13594 _setOption: function( key, value ) {
13595 this._super( key, value );
13597 if ( key === "handle" ) {
13598 this._setHandleClassName();
13602 _setHandleClassName: function() {
13603 this.element.find( ".ui-sortable-handle" ).removeClass( "ui-sortable-handle" );
13604 $.each( this.items, function() {
13605 ( this.instance.options.handle ?
13606 this.item.find( this.instance.options.handle ) : this.item )
13607 .addClass( "ui-sortable-handle" );
13611 _destroy: function() {
13613 .removeClass( "ui-sortable ui-sortable-disabled" )
13614 .find( ".ui-sortable-handle" )
13615 .removeClass( "ui-sortable-handle" );
13616 this._mouseDestroy();
13618 for ( var i = this.items.length - 1; i >= 0; i-- ) {
13619 this.items[i].item.removeData(this.widgetName + "-item");
13625 _mouseCapture: function(event, overrideHandle) {
13626 var currentItem = null,
13627 validHandle = false,
13630 if (this.reverting) {
13634 if(this.options.disabled || this.options.type === "static") {
13638 //We have to refresh the items data once first
13639 this._refreshItems(event);
13641 //Find out if the clicked node (or one of its parents) is a actual item in this.items
13642 $(event.target).parents().each(function() {
13643 if($.data(this, that.widgetName + "-item") === that) {
13644 currentItem = $(this);
13648 if($.data(event.target, that.widgetName + "-item") === that) {
13649 currentItem = $(event.target);
13655 if(this.options.handle && !overrideHandle) {
13656 $(this.options.handle, currentItem).find("*").addBack().each(function() {
13657 if(this === event.target) {
13658 validHandle = true;
13666 this.currentItem = currentItem;
13667 this._removeCurrentsFromItems();
13672 _mouseStart: function(event, overrideHandle, noActivation) {
13677 this.currentContainer = this;
13679 //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
13680 this.refreshPositions();
13682 //Create and append the visible helper
13683 this.helper = this._createHelper(event);
13685 //Cache the helper size
13686 this._cacheHelperProportions();
13689 * - Position generation -
13690 * This block generates everything position related - it's the core of draggables.
13693 //Cache the margins of the original element
13694 this._cacheMargins();
13696 //Get the next scrolling parent
13697 this.scrollParent = this.helper.scrollParent();
13699 //The element's absolute position on the page minus margins
13700 this.offset = this.currentItem.offset();
13702 top: this.offset.top - this.margins.top,
13703 left: this.offset.left - this.margins.left
13706 $.extend(this.offset, {
13707 click: { //Where the click happened, relative to the element
13708 left: event.pageX - this.offset.left,
13709 top: event.pageY - this.offset.top
13711 parent: this._getParentOffset(),
13712 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
13715 // Only after we got the offset, we can change the helper's position to absolute
13716 // TODO: Still need to figure out a way to make relative sorting possible
13717 this.helper.css("position", "absolute");
13718 this.cssPosition = this.helper.css("position");
13720 //Generate the original position
13721 this.originalPosition = this._generatePosition(event);
13722 this.originalPageX = event.pageX;
13723 this.originalPageY = event.pageY;
13725 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
13726 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
13728 //Cache the former DOM position
13729 this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };
13731 //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
13732 if(this.helper[0] !== this.currentItem[0]) {
13733 this.currentItem.hide();
13736 //Create the placeholder
13737 this._createPlaceholder();
13739 //Set a containment if given in the options
13740 if(o.containment) {
13741 this._setContainment();
13744 if( o.cursor && o.cursor !== "auto" ) { // cursor option
13745 body = this.document.find( "body" );
13748 this.storedCursor = body.css( "cursor" );
13749 body.css( "cursor", o.cursor );
13751 this.storedStylesheet = $( "<style>*{ cursor: "+o.cursor+" !important; }</style>" ).appendTo( body );
13754 if(o.opacity) { // opacity option
13755 if (this.helper.css("opacity")) {
13756 this._storedOpacity = this.helper.css("opacity");
13758 this.helper.css("opacity", o.opacity);
13761 if(o.zIndex) { // zIndex option
13762 if (this.helper.css("zIndex")) {
13763 this._storedZIndex = this.helper.css("zIndex");
13765 this.helper.css("zIndex", o.zIndex);
13768 //Prepare scrolling
13769 if(this.scrollParent[0] !== this.document[0] && this.scrollParent[0].tagName !== "HTML") {
13770 this.overflowOffset = this.scrollParent.offset();
13774 this._trigger("start", event, this._uiHash());
13776 //Recache the helper size
13777 if(!this._preserveHelperProportions) {
13778 this._cacheHelperProportions();
13782 //Post "activate" events to possible containers
13783 if( !noActivation ) {
13784 for ( i = this.containers.length - 1; i >= 0; i-- ) {
13785 this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
13789 //Prepare possible droppables
13790 if($.ui.ddmanager) {
13791 $.ui.ddmanager.current = this;
13794 if ($.ui.ddmanager && !o.dropBehaviour) {
13795 $.ui.ddmanager.prepareOffsets(this, event);
13798 this.dragging = true;
13800 this.helper.addClass("ui-sortable-helper");
13801 this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
13806 _mouseDrag: function(event) {
13807 var i, item, itemElement, intersection,
13811 //Compute the helpers position
13812 this.position = this._generatePosition(event);
13813 this.positionAbs = this._convertPositionTo("absolute");
13815 if (!this.lastPositionAbs) {
13816 this.lastPositionAbs = this.positionAbs;
13820 if(this.options.scroll) {
13821 if(this.scrollParent[0] !== this.document[0] && this.scrollParent[0].tagName !== "HTML") {
13823 if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
13824 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
13825 } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) {
13826 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
13829 if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
13830 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
13831 } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) {
13832 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
13837 if(event.pageY - this.document.scrollTop() < o.scrollSensitivity) {
13838 scrolled = this.document.scrollTop(this.document.scrollTop() - o.scrollSpeed);
13839 } else if(this.window.height() - (event.pageY - this.document.scrollTop()) < o.scrollSensitivity) {
13840 scrolled = this.document.scrollTop(this.document.scrollTop() + o.scrollSpeed);
13843 if(event.pageX - this.document.scrollLeft() < o.scrollSensitivity) {
13844 scrolled = this.document.scrollLeft(this.document.scrollLeft() - o.scrollSpeed);
13845 } else if(this.window.width() - (event.pageX - this.document.scrollLeft()) < o.scrollSensitivity) {
13846 scrolled = this.document.scrollLeft(this.document.scrollLeft() + o.scrollSpeed);
13851 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
13852 $.ui.ddmanager.prepareOffsets(this, event);
13856 //Regenerate the absolute position used for position checks
13857 this.positionAbs = this._convertPositionTo("absolute");
13859 //Set the helper position
13860 if(!this.options.axis || this.options.axis !== "y") {
13861 this.helper[0].style.left = this.position.left+"px";
13863 if(!this.options.axis || this.options.axis !== "x") {
13864 this.helper[0].style.top = this.position.top+"px";
13868 for (i = this.items.length - 1; i >= 0; i--) {
13870 //Cache variables and intersection, continue if no intersection
13871 item = this.items[i];
13872 itemElement = item.item[0];
13873 intersection = this._intersectsWithPointer(item);
13874 if (!intersection) {
13878 // Only put the placeholder inside the current Container, skip all
13879 // items from other containers. This works because when moving
13880 // an item from one container to another the
13881 // currentContainer is switched before the placeholder is moved.
13883 // Without this, moving items in "sub-sortables" can cause
13884 // the placeholder to jitter between the outer and inner container.
13885 if (item.instance !== this.currentContainer) {
13889 // cannot intersect with itself
13890 // no useless actions that have been done before
13891 // no action if the item moved is the parent of the item checked
13892 if (itemElement !== this.currentItem[0] &&
13893 this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement &&
13894 !$.contains(this.placeholder[0], itemElement) &&
13895 (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true)
13898 this.direction = intersection === 1 ? "down" : "up";
13900 if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) {
13901 this._rearrange(event, item);
13906 this._trigger("change", event, this._uiHash());
13911 //Post events to containers
13912 this._contactContainers(event);
13914 //Interconnect with droppables
13915 if($.ui.ddmanager) {
13916 $.ui.ddmanager.drag(this, event);
13920 this._trigger("sort", event, this._uiHash());
13922 this.lastPositionAbs = this.positionAbs;
13927 _mouseStop: function(event, noPropagation) {
13933 //If we are using droppables, inform the manager about the drop
13934 if ($.ui.ddmanager && !this.options.dropBehaviour) {
13935 $.ui.ddmanager.drop(this, event);
13938 if(this.options.revert) {
13940 cur = this.placeholder.offset(),
13941 axis = this.options.axis,
13944 if ( !axis || axis === "x" ) {
13945 animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === this.document[0].body ? 0 : this.offsetParent[0].scrollLeft);
13947 if ( !axis || axis === "y" ) {
13948 animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === this.document[0].body ? 0 : this.offsetParent[0].scrollTop);
13950 this.reverting = true;
13951 $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() {
13952 that._clear(event);
13955 this._clear(event, noPropagation);
13962 cancel: function() {
13964 if(this.dragging) {
13966 this._mouseUp({ target: null });
13968 if(this.options.helper === "original") {
13969 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
13971 this.currentItem.show();
13974 //Post deactivating events to containers
13975 for (var i = this.containers.length - 1; i >= 0; i--){
13976 this.containers[i]._trigger("deactivate", null, this._uiHash(this));
13977 if(this.containers[i].containerCache.over) {
13978 this.containers[i]._trigger("out", null, this._uiHash(this));
13979 this.containers[i].containerCache.over = 0;
13985 if (this.placeholder) {
13986 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
13987 if(this.placeholder[0].parentNode) {
13988 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
13990 if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) {
13991 this.helper.remove();
14001 if(this.domPosition.prev) {
14002 $(this.domPosition.prev).after(this.currentItem);
14004 $(this.domPosition.parent).prepend(this.currentItem);
14012 serialize: function(o) {
14014 var items = this._getItemsAsjQuery(o && o.connected),
14018 $(items).each(function() {
14019 var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/));
14021 str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2]));
14025 if(!str.length && o.key) {
14026 str.push(o.key + "=");
14029 return str.join("&");
14033 toArray: function(o) {
14035 var items = this._getItemsAsjQuery(o && o.connected),
14040 items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); });
14045 /* Be careful with the following core functions */
14046 _intersectsWith: function(item) {
14048 var x1 = this.positionAbs.left,
14049 x2 = x1 + this.helperProportions.width,
14050 y1 = this.positionAbs.top,
14051 y2 = y1 + this.helperProportions.height,
14053 r = l + item.width,
14055 b = t + item.height,
14056 dyClick = this.offset.click.top,
14057 dxClick = this.offset.click.left,
14058 isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ),
14059 isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ),
14060 isOverElement = isOverElementHeight && isOverElementWidth;
14062 if ( this.options.tolerance === "pointer" ||
14063 this.options.forcePointerForContainers ||
14064 (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"])
14066 return isOverElement;
14069 return (l < x1 + (this.helperProportions.width / 2) && // Right Half
14070 x2 - (this.helperProportions.width / 2) < r && // Left Half
14071 t < y1 + (this.helperProportions.height / 2) && // Bottom Half
14072 y2 - (this.helperProportions.height / 2) < b ); // Top Half
14077 _intersectsWithPointer: function(item) {
14079 var isOverElementHeight = (this.options.axis === "x") || this._isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
14080 isOverElementWidth = (this.options.axis === "y") || this._isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
14081 isOverElement = isOverElementHeight && isOverElementWidth,
14082 verticalDirection = this._getDragVerticalDirection(),
14083 horizontalDirection = this._getDragHorizontalDirection();
14085 if (!isOverElement) {
14089 return this.floating ?
14090 ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 )
14091 : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) );
14095 _intersectsWithSides: function(item) {
14097 var isOverBottomHalf = this._isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
14098 isOverRightHalf = this._isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
14099 verticalDirection = this._getDragVerticalDirection(),
14100 horizontalDirection = this._getDragHorizontalDirection();
14102 if (this.floating && horizontalDirection) {
14103 return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf));
14105 return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf));
14110 _getDragVerticalDirection: function() {
14111 var delta = this.positionAbs.top - this.lastPositionAbs.top;
14112 return delta !== 0 && (delta > 0 ? "down" : "up");
14115 _getDragHorizontalDirection: function() {
14116 var delta = this.positionAbs.left - this.lastPositionAbs.left;
14117 return delta !== 0 && (delta > 0 ? "right" : "left");
14120 refresh: function(event) {
14121 this._refreshItems(event);
14122 this._setHandleClassName();
14123 this.refreshPositions();
14127 _connectWith: function() {
14128 var options = this.options;
14129 return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith;
14132 _getItemsAsjQuery: function(connected) {
14134 var i, j, cur, inst,
14137 connectWith = this._connectWith();
14139 if(connectWith && connected) {
14140 for (i = connectWith.length - 1; i >= 0; i--){
14141 cur = $(connectWith[i], this.document[0]);
14142 for ( j = cur.length - 1; j >= 0; j--){
14143 inst = $.data(cur[j], this.widgetFullName);
14144 if(inst && inst !== this && !inst.options.disabled) {
14145 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]);
14151 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]);
14153 function addItems() {
14154 items.push( this );
14156 for (i = queries.length - 1; i >= 0; i--){
14157 queries[i][0].each( addItems );
14164 _removeCurrentsFromItems: function() {
14166 var list = this.currentItem.find(":data(" + this.widgetName + "-item)");
14168 this.items = $.grep(this.items, function (item) {
14169 for (var j=0; j < list.length; j++) {
14170 if(list[j] === item.item[0]) {
14179 _refreshItems: function(event) {
14182 this.containers = [this];
14184 var i, j, cur, inst, targetData, _queries, item, queriesLength,
14185 items = this.items,
14186 queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]],
14187 connectWith = this._connectWith();
14189 if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down
14190 for (i = connectWith.length - 1; i >= 0; i--){
14191 cur = $(connectWith[i], this.document[0]);
14192 for (j = cur.length - 1; j >= 0; j--){
14193 inst = $.data(cur[j], this.widgetFullName);
14194 if(inst && inst !== this && !inst.options.disabled) {
14195 queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
14196 this.containers.push(inst);
14202 for (i = queries.length - 1; i >= 0; i--) {
14203 targetData = queries[i][1];
14204 _queries = queries[i][0];
14206 for (j=0, queriesLength = _queries.length; j < queriesLength; j++) {
14207 item = $(_queries[j]);
14209 item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager)
14213 instance: targetData,
14214 width: 0, height: 0,
14222 refreshPositions: function(fast) {
14224 //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
14225 if(this.offsetParent && this.helper) {
14226 this.offset.parent = this._getParentOffset();
14231 for (i = this.items.length - 1; i >= 0; i--){
14232 item = this.items[i];
14234 //We ignore calculating positions of all connected containers when we're not over them
14235 if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) {
14239 t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
14242 item.width = t.outerWidth();
14243 item.height = t.outerHeight();
14247 item.left = p.left;
14251 if(this.options.custom && this.options.custom.refreshContainers) {
14252 this.options.custom.refreshContainers.call(this);
14254 for (i = this.containers.length - 1; i >= 0; i--){
14255 p = this.containers[i].element.offset();
14256 this.containers[i].containerCache.left = p.left;
14257 this.containers[i].containerCache.top = p.top;
14258 this.containers[i].containerCache.width = this.containers[i].element.outerWidth();
14259 this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
14266 _createPlaceholder: function(that) {
14267 that = that || this;
14271 if(!o.placeholder || o.placeholder.constructor === String) {
14272 className = o.placeholder;
14274 element: function() {
14276 var nodeName = that.currentItem[0].nodeName.toLowerCase(),
14277 element = $( "<" + nodeName + ">", that.document[0] )
14278 .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder")
14279 .removeClass("ui-sortable-helper");
14281 if ( nodeName === "tr" ) {
14282 that.currentItem.children().each(function() {
14283 $( "<td> </td>", that.document[0] )
14284 .attr( "colspan", $( this ).attr( "colspan" ) || 1 )
14285 .appendTo( element );
14287 } else if ( nodeName === "img" ) {
14288 element.attr( "src", that.currentItem.attr( "src" ) );
14291 if ( !className ) {
14292 element.css( "visibility", "hidden" );
14297 update: function(container, p) {
14299 // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that
14300 // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified
14301 if(className && !o.forcePlaceholderSize) {
14305 //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
14306 if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); }
14307 if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); }
14312 //Create the placeholder
14313 that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem));
14315 //Append it after the actual current item
14316 that.currentItem.after(that.placeholder);
14318 //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
14319 o.placeholder.update(that, that.placeholder);
14323 _contactContainers: function(event) {
14324 var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom, floating, axis,
14325 innermostContainer = null,
14326 innermostIndex = null;
14328 // get innermost container that intersects with item
14329 for (i = this.containers.length - 1; i >= 0; i--) {
14331 // never consider a container that's located within the item itself
14332 if($.contains(this.currentItem[0], this.containers[i].element[0])) {
14336 if(this._intersectsWith(this.containers[i].containerCache)) {
14338 // if we've already found a container and it's more "inner" than this, then continue
14339 if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) {
14343 innermostContainer = this.containers[i];
14344 innermostIndex = i;
14347 // container doesn't intersect. trigger "out" event if necessary
14348 if(this.containers[i].containerCache.over) {
14349 this.containers[i]._trigger("out", event, this._uiHash(this));
14350 this.containers[i].containerCache.over = 0;
14356 // if no intersecting containers found, return
14357 if(!innermostContainer) {
14361 // move the item into the container if it's not there already
14362 if(this.containers.length === 1) {
14363 if (!this.containers[innermostIndex].containerCache.over) {
14364 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
14365 this.containers[innermostIndex].containerCache.over = 1;
14369 //When entering a new container, we will find the item with the least distance and append our item near it
14371 itemWithLeastDistance = null;
14372 floating = innermostContainer.floating || this._isFloating(this.currentItem);
14373 posProperty = floating ? "left" : "top";
14374 sizeProperty = floating ? "width" : "height";
14375 axis = floating ? "clientX" : "clientY";
14377 for (j = this.items.length - 1; j >= 0; j--) {
14378 if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) {
14381 if(this.items[j].item[0] === this.currentItem[0]) {
14385 cur = this.items[j].item.offset()[posProperty];
14386 nearBottom = false;
14387 if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) {
14391 if ( Math.abs( event[ axis ] - cur ) < dist ) {
14392 dist = Math.abs( event[ axis ] - cur );
14393 itemWithLeastDistance = this.items[ j ];
14394 this.direction = nearBottom ? "up": "down";
14398 //Check if dropOnEmpty is enabled
14399 if(!itemWithLeastDistance && !this.options.dropOnEmpty) {
14403 if(this.currentContainer === this.containers[innermostIndex]) {
14404 if ( !this.currentContainer.containerCache.over ) {
14405 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() );
14406 this.currentContainer.containerCache.over = 1;
14411 itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true);
14412 this._trigger("change", event, this._uiHash());
14413 this.containers[innermostIndex]._trigger("change", event, this._uiHash(this));
14414 this.currentContainer = this.containers[innermostIndex];
14416 //Update the placeholder
14417 this.options.placeholder.update(this.currentContainer, this.placeholder);
14419 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
14420 this.containers[innermostIndex].containerCache.over = 1;
14426 _createHelper: function(event) {
14428 var o = this.options,
14429 helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem);
14431 //Add the helper to the DOM if that didn't happen already
14432 if(!helper.parents("body").length) {
14433 $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
14436 if(helper[0] === this.currentItem[0]) {
14437 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") };
14440 if(!helper[0].style.width || o.forceHelperSize) {
14441 helper.width(this.currentItem.width());
14443 if(!helper[0].style.height || o.forceHelperSize) {
14444 helper.height(this.currentItem.height());
14451 _adjustOffsetFromHelper: function(obj) {
14452 if (typeof obj === "string") {
14453 obj = obj.split(" ");
14455 if ($.isArray(obj)) {
14456 obj = {left: +obj[0], top: +obj[1] || 0};
14458 if ("left" in obj) {
14459 this.offset.click.left = obj.left + this.margins.left;
14461 if ("right" in obj) {
14462 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
14464 if ("top" in obj) {
14465 this.offset.click.top = obj.top + this.margins.top;
14467 if ("bottom" in obj) {
14468 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
14472 _getParentOffset: function() {
14475 //Get the offsetParent and cache its position
14476 this.offsetParent = this.helper.offsetParent();
14477 var po = this.offsetParent.offset();
14479 // This is a special case where we need to modify a offset calculated on start, since the following happened:
14480 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
14481 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
14482 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
14483 if(this.cssPosition === "absolute" && this.scrollParent[0] !== this.document[0] && $.contains(this.scrollParent[0], this.offsetParent[0])) {
14484 po.left += this.scrollParent.scrollLeft();
14485 po.top += this.scrollParent.scrollTop();
14488 // This needs to be actually done for all browsers, since pageX/pageY includes this information
14489 // with an ugly IE fix
14490 if( this.offsetParent[0] === this.document[0].body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
14491 po = { top: 0, left: 0 };
14495 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
14496 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
14501 _getRelativeOffset: function() {
14503 if(this.cssPosition === "relative") {
14504 var p = this.currentItem.position();
14506 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
14507 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
14510 return { top: 0, left: 0 };
14515 _cacheMargins: function() {
14517 left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
14518 top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
14522 _cacheHelperProportions: function() {
14523 this.helperProportions = {
14524 width: this.helper.outerWidth(),
14525 height: this.helper.outerHeight()
14529 _setContainment: function() {
14533 if(o.containment === "parent") {
14534 o.containment = this.helper[0].parentNode;
14536 if(o.containment === "document" || o.containment === "window") {
14537 this.containment = [
14538 0 - this.offset.relative.left - this.offset.parent.left,
14539 0 - this.offset.relative.top - this.offset.parent.top,
14540 o.containment === "document" ? this.document.width() : this.window.width() - this.helperProportions.width - this.margins.left,
14541 (o.containment === "document" ? this.document.width() : this.window.height() || this.document[0].body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
14545 if(!(/^(document|window|parent)$/).test(o.containment)) {
14546 ce = $(o.containment)[0];
14547 co = $(o.containment).offset();
14548 over = ($(ce).css("overflow") !== "hidden");
14550 this.containment = [
14551 co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
14552 co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
14553 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,
14554 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
14560 _convertPositionTo: function(d, pos) {
14563 pos = this.position;
14565 var mod = d === "absolute" ? 1 : -1,
14566 scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== this.document[0] && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent,
14567 scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
14571 pos.top + // The absolute mouse position
14572 this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
14573 this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
14574 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
14577 pos.left + // The absolute mouse position
14578 this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
14579 this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
14580 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
14586 _generatePosition: function(event) {
14590 pageX = event.pageX,
14591 pageY = event.pageY,
14592 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);
14594 // This is another very weird special case that only happens for relative elements:
14595 // 1. If the css position is relative
14596 // 2. and the scroll parent is the document or similar to the offset parent
14597 // we have to refresh the relative offset during the scroll so there are no jumps
14598 if(this.cssPosition === "relative" && !(this.scrollParent[0] !== this.document[0] && this.scrollParent[0] !== this.offsetParent[0])) {
14599 this.offset.relative = this._getRelativeOffset();
14603 * - Position constraining -
14604 * Constrain the position to a mix of grid, containment.
14607 if(this.originalPosition) { //If we are not dragging yet, we won't check for options
14609 if(this.containment) {
14610 if(event.pageX - this.offset.click.left < this.containment[0]) {
14611 pageX = this.containment[0] + this.offset.click.left;
14613 if(event.pageY - this.offset.click.top < this.containment[1]) {
14614 pageY = this.containment[1] + this.offset.click.top;
14616 if(event.pageX - this.offset.click.left > this.containment[2]) {
14617 pageX = this.containment[2] + this.offset.click.left;
14619 if(event.pageY - this.offset.click.top > this.containment[3]) {
14620 pageY = this.containment[3] + this.offset.click.top;
14625 top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
14626 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;
14628 left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
14629 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;
14636 pageY - // The absolute mouse position
14637 this.offset.click.top - // Click offset (relative to the element)
14638 this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
14639 this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
14640 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
14643 pageX - // The absolute mouse position
14644 this.offset.click.left - // Click offset (relative to the element)
14645 this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
14646 this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
14647 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
14653 _rearrange: function(event, i, a, hardRefresh) {
14655 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));
14657 //Various things done here to improve the performance:
14658 // 1. we create a setTimeout, that calls refreshPositions
14659 // 2. on the instance, we have a counter variable, that get's higher after every append
14660 // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
14661 // 4. this lets only the last addition to the timeout stack through
14662 this.counter = this.counter ? ++this.counter : 1;
14663 var counter = this.counter;
14665 this._delay(function() {
14666 if(counter === this.counter) {
14667 this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
14673 _clear: function(event, noPropagation) {
14675 this.reverting = false;
14676 // We delay all events that have to be triggered to after the point where the placeholder has been removed and
14677 // everything else normalized again
14679 delayedTriggers = [];
14681 // We first have to update the dom position of the actual currentItem
14682 // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
14683 if(!this._noFinalSort && this.currentItem.parent().length) {
14684 this.placeholder.before(this.currentItem);
14686 this._noFinalSort = null;
14688 if(this.helper[0] === this.currentItem[0]) {
14689 for(i in this._storedCSS) {
14690 if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") {
14691 this._storedCSS[i] = "";
14694 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
14696 this.currentItem.show();
14699 if(this.fromOutside && !noPropagation) {
14700 delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
14702 if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) {
14703 delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed
14706 // Check if the items Container has Changed and trigger appropriate
14708 if (this !== this.currentContainer) {
14709 if(!noPropagation) {
14710 delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); });
14711 delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
14712 delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
14717 //Post events to containers
14718 function delayEvent( type, instance, container ) {
14719 return function( event ) {
14720 container._trigger( type, event, instance._uiHash( instance ) );
14723 for (i = this.containers.length - 1; i >= 0; i--){
14724 if (!noPropagation) {
14725 delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) );
14727 if(this.containers[i].containerCache.over) {
14728 delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) );
14729 this.containers[i].containerCache.over = 0;
14733 //Do what was originally in plugins
14734 if ( this.storedCursor ) {
14735 this.document.find( "body" ).css( "cursor", this.storedCursor );
14736 this.storedStylesheet.remove();
14738 if(this._storedOpacity) {
14739 this.helper.css("opacity", this._storedOpacity);
14741 if(this._storedZIndex) {
14742 this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex);
14745 this.dragging = false;
14747 if(!noPropagation) {
14748 this._trigger("beforeStop", event, this._uiHash());
14751 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
14752 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
14754 if ( !this.cancelHelperRemoval ) {
14755 if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
14756 this.helper.remove();
14758 this.helper = null;
14761 if(!noPropagation) {
14762 for (i=0; i < delayedTriggers.length; i++) {
14763 delayedTriggers[i].call(this, event);
14764 } //Trigger all delayed events
14765 this._trigger("stop", event, this._uiHash());
14768 this.fromOutside = false;
14769 return !this.cancelHelperRemoval;
14773 _trigger: function() {
14774 if ($.Widget.prototype._trigger.apply(this, arguments) === false) {
14779 _uiHash: function(_inst) {
14780 var inst = _inst || this;
14782 helper: inst.helper,
14783 placeholder: inst.placeholder || $([]),
14784 position: inst.position,
14785 originalPosition: inst.originalPosition,
14786 offset: inst.positionAbs,
14787 item: inst.currentItem,
14788 sender: _inst ? _inst.element : null
14796 * jQuery UI Spinner 1.11.3
14797 * http://jqueryui.com
14799 * Copyright jQuery Foundation and other contributors
14800 * Released under the MIT license.
14801 * http://jquery.org/license
14803 * http://api.jqueryui.com/spinner/
14807 function spinner_modifier( fn ) {
14808 return function() {
14809 var previous = this.element.val();
14810 fn.apply( this, arguments );
14812 if ( previous !== this.element.val() ) {
14813 this._trigger( "change" );
14818 var spinner = $.widget( "ui.spinner", {
14820 defaultElement: "<input>",
14821 widgetEventPrefix: "spin",
14825 down: "ui-icon-triangle-1-s",
14826 up: "ui-icon-triangle-1-n"
14831 numberFormat: null,
14841 _create: function() {
14842 // handle string values that need to be parsed
14843 this._setOption( "max", this.options.max );
14844 this._setOption( "min", this.options.min );
14845 this._setOption( "step", this.options.step );
14847 // Only format if there is a value, prevents the field from being marked
14848 // as invalid in Firefox, see #9573.
14849 if ( this.value() !== "" ) {
14850 // Format the value, but don't constrain.
14851 this._value( this.element.val(), true );
14855 this._on( this._events );
14858 // turning off autocomplete prevents the browser from remembering the
14859 // value when navigating through history, so we re-enable autocomplete
14860 // if the page is unloaded before the widget is destroyed. #7790
14861 this._on( this.window, {
14862 beforeunload: function() {
14863 this.element.removeAttr( "autocomplete" );
14868 _getCreateOptions: function() {
14870 element = this.element;
14872 $.each( [ "min", "max", "step" ], function( i, option ) {
14873 var value = element.attr( option );
14874 if ( value !== undefined && value.length ) {
14875 options[ option ] = value;
14883 keydown: function( event ) {
14884 if ( this._start( event ) && this._keydown( event ) ) {
14885 event.preventDefault();
14889 focus: function() {
14890 this.previous = this.element.val();
14892 blur: function( event ) {
14893 if ( this.cancelBlur ) {
14894 delete this.cancelBlur;
14900 if ( this.previous !== this.element.val() ) {
14901 this._trigger( "change", event );
14904 mousewheel: function( event, delta ) {
14908 if ( !this.spinning && !this._start( event ) ) {
14912 this._spin( (delta > 0 ? 1 : -1) * this.options.step, event );
14913 clearTimeout( this.mousewheelTimer );
14914 this.mousewheelTimer = this._delay(function() {
14915 if ( this.spinning ) {
14916 this._stop( event );
14919 event.preventDefault();
14921 "mousedown .ui-spinner-button": function( event ) {
14924 // We never want the buttons to have focus; whenever the user is
14925 // interacting with the spinner, the focus should be on the input.
14926 // If the input is focused then this.previous is properly set from
14927 // when the input first received focus. If the input is not focused
14928 // then we need to set this.previous based on the value before spinning.
14929 previous = this.element[0] === this.document[0].activeElement ?
14930 this.previous : this.element.val();
14931 function checkFocus() {
14932 var isActive = this.element[0] === this.document[0].activeElement;
14934 this.element.focus();
14935 this.previous = previous;
14937 // IE sets focus asynchronously, so we need to check if focus
14938 // moved off of the input because the user clicked on the button.
14939 this._delay(function() {
14940 this.previous = previous;
14945 // ensure focus is on (or stays on) the text field
14946 event.preventDefault();
14947 checkFocus.call( this );
14950 // IE doesn't prevent moving focus even with event.preventDefault()
14951 // so we set a flag to know when we should ignore the blur event
14952 // and check (again) if focus moved off of the input.
14953 this.cancelBlur = true;
14954 this._delay(function() {
14955 delete this.cancelBlur;
14956 checkFocus.call( this );
14959 if ( this._start( event ) === false ) {
14963 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
14965 "mouseup .ui-spinner-button": "_stop",
14966 "mouseenter .ui-spinner-button": function( event ) {
14967 // button will add ui-state-active if mouse was down while mouseleave and kept down
14968 if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
14972 if ( this._start( event ) === false ) {
14975 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
14977 // TODO: do we really want to consider this a stop?
14978 // shouldn't we just stop the repeater and wait until mouseup before
14979 // we trigger the stop event?
14980 "mouseleave .ui-spinner-button": "_stop"
14983 _draw: function() {
14984 var uiSpinner = this.uiSpinner = this.element
14985 .addClass( "ui-spinner-input" )
14986 .attr( "autocomplete", "off" )
14987 .wrap( this._uiSpinnerHtml() )
14990 .append( this._buttonHtml() );
14992 this.element.attr( "role", "spinbutton" );
14995 this.buttons = uiSpinner.find( ".ui-spinner-button" )
14996 .attr( "tabIndex", -1 )
14998 .removeClass( "ui-corner-all" );
15000 // IE 6 doesn't understand height: 50% for the buttons
15001 // unless the wrapper has an explicit height
15002 if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) &&
15003 uiSpinner.height() > 0 ) {
15004 uiSpinner.height( uiSpinner.height() );
15007 // disable spinner if element was already disabled
15008 if ( this.options.disabled ) {
15013 _keydown: function( event ) {
15014 var options = this.options,
15015 keyCode = $.ui.keyCode;
15017 switch ( event.keyCode ) {
15019 this._repeat( null, 1, event );
15022 this._repeat( null, -1, event );
15024 case keyCode.PAGE_UP:
15025 this._repeat( null, options.page, event );
15027 case keyCode.PAGE_DOWN:
15028 this._repeat( null, -options.page, event );
15035 _uiSpinnerHtml: function() {
15036 return "<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>";
15039 _buttonHtml: function() {
15041 "<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>" +
15042 "<span class='ui-icon " + this.options.icons.up + "'>▲</span>" +
15044 "<a class='ui-spinner-button ui-spinner-down ui-corner-br'>" +
15045 "<span class='ui-icon " + this.options.icons.down + "'>▼</span>" +
15049 _start: function( event ) {
15050 if ( !this.spinning && this._trigger( "start", event ) === false ) {
15054 if ( !this.counter ) {
15057 this.spinning = true;
15061 _repeat: function( i, steps, event ) {
15064 clearTimeout( this.timer );
15065 this.timer = this._delay(function() {
15066 this._repeat( 40, steps, event );
15069 this._spin( steps * this.options.step, event );
15072 _spin: function( step, event ) {
15073 var value = this.value() || 0;
15075 if ( !this.counter ) {
15079 value = this._adjustValue( value + step * this._increment( this.counter ) );
15081 if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) {
15082 this._value( value );
15087 _increment: function( i ) {
15088 var incremental = this.options.incremental;
15090 if ( incremental ) {
15091 return $.isFunction( incremental ) ?
15093 Math.floor( i * i * i / 50000 - i * i / 500 + 17 * i / 200 + 1 );
15099 _precision: function() {
15100 var precision = this._precisionOf( this.options.step );
15101 if ( this.options.min !== null ) {
15102 precision = Math.max( precision, this._precisionOf( this.options.min ) );
15107 _precisionOf: function( num ) {
15108 var str = num.toString(),
15109 decimal = str.indexOf( "." );
15110 return decimal === -1 ? 0 : str.length - decimal - 1;
15113 _adjustValue: function( value ) {
15114 var base, aboveMin,
15115 options = this.options;
15117 // make sure we're at a valid step
15118 // - find out where we are relative to the base (min or 0)
15119 base = options.min !== null ? options.min : 0;
15120 aboveMin = value - base;
15121 // - round to the nearest step
15122 aboveMin = Math.round(aboveMin / options.step) * options.step;
15123 // - rounding is based on 0, so adjust back to our base
15124 value = base + aboveMin;
15126 // fix precision from bad JS floating point math
15127 value = parseFloat( value.toFixed( this._precision() ) );
15130 if ( options.max !== null && value > options.max) {
15131 return options.max;
15133 if ( options.min !== null && value < options.min ) {
15134 return options.min;
15140 _stop: function( event ) {
15141 if ( !this.spinning ) {
15145 clearTimeout( this.timer );
15146 clearTimeout( this.mousewheelTimer );
15148 this.spinning = false;
15149 this._trigger( "stop", event );
15152 _setOption: function( key, value ) {
15153 if ( key === "culture" || key === "numberFormat" ) {
15154 var prevValue = this._parse( this.element.val() );
15155 this.options[ key ] = value;
15156 this.element.val( this._format( prevValue ) );
15160 if ( key === "max" || key === "min" || key === "step" ) {
15161 if ( typeof value === "string" ) {
15162 value = this._parse( value );
15165 if ( key === "icons" ) {
15166 this.buttons.first().find( ".ui-icon" )
15167 .removeClass( this.options.icons.up )
15168 .addClass( value.up );
15169 this.buttons.last().find( ".ui-icon" )
15170 .removeClass( this.options.icons.down )
15171 .addClass( value.down );
15174 this._super( key, value );
15176 if ( key === "disabled" ) {
15177 this.widget().toggleClass( "ui-state-disabled", !!value );
15178 this.element.prop( "disabled", !!value );
15179 this.buttons.button( value ? "disable" : "enable" );
15183 _setOptions: spinner_modifier(function( options ) {
15184 this._super( options );
15187 _parse: function( val ) {
15188 if ( typeof val === "string" && val !== "" ) {
15189 val = window.Globalize && this.options.numberFormat ?
15190 Globalize.parseFloat( val, 10, this.options.culture ) : +val;
15192 return val === "" || isNaN( val ) ? null : val;
15195 _format: function( value ) {
15196 if ( value === "" ) {
15199 return window.Globalize && this.options.numberFormat ?
15200 Globalize.format( value, this.options.numberFormat, this.options.culture ) :
15204 _refresh: function() {
15205 this.element.attr({
15206 "aria-valuemin": this.options.min,
15207 "aria-valuemax": this.options.max,
15208 // TODO: what should we do with values that can't be parsed?
15209 "aria-valuenow": this._parse( this.element.val() )
15213 isValid: function() {
15214 var value = this.value();
15217 if ( value === null ) {
15221 // if value gets adjusted, it's invalid
15222 return value === this._adjustValue( value );
15225 // update the value without triggering change
15226 _value: function( value, allowAny ) {
15228 if ( value !== "" ) {
15229 parsed = this._parse( value );
15230 if ( parsed !== null ) {
15232 parsed = this._adjustValue( parsed );
15234 value = this._format( parsed );
15237 this.element.val( value );
15241 _destroy: function() {
15243 .removeClass( "ui-spinner-input" )
15244 .prop( "disabled", false )
15245 .removeAttr( "autocomplete" )
15246 .removeAttr( "role" )
15247 .removeAttr( "aria-valuemin" )
15248 .removeAttr( "aria-valuemax" )
15249 .removeAttr( "aria-valuenow" );
15250 this.uiSpinner.replaceWith( this.element );
15253 stepUp: spinner_modifier(function( steps ) {
15254 this._stepUp( steps );
15256 _stepUp: function( steps ) {
15257 if ( this._start() ) {
15258 this._spin( (steps || 1) * this.options.step );
15263 stepDown: spinner_modifier(function( steps ) {
15264 this._stepDown( steps );
15266 _stepDown: function( steps ) {
15267 if ( this._start() ) {
15268 this._spin( (steps || 1) * -this.options.step );
15273 pageUp: spinner_modifier(function( pages ) {
15274 this._stepUp( (pages || 1) * this.options.page );
15277 pageDown: spinner_modifier(function( pages ) {
15278 this._stepDown( (pages || 1) * this.options.page );
15281 value: function( newVal ) {
15282 if ( !arguments.length ) {
15283 return this._parse( this.element.val() );
15285 spinner_modifier( this._value ).call( this, newVal );
15288 widget: function() {
15289 return this.uiSpinner;
15295 * jQuery UI Tabs 1.11.3
15296 * http://jqueryui.com
15298 * Copyright jQuery Foundation and other contributors
15299 * Released under the MIT license.
15300 * http://jquery.org/license
15302 * http://api.jqueryui.com/tabs/
15306 var tabs = $.widget( "ui.tabs", {
15311 collapsible: false,
15313 heightStyle: "content",
15319 beforeActivate: null,
15324 _isLocal: (function() {
15325 var rhash = /#.*$/;
15327 return function( anchor ) {
15328 var anchorUrl, locationUrl;
15331 // IE7 doesn't normalize the href property when set via script (#9317)
15332 anchor = anchor.cloneNode( false );
15334 anchorUrl = anchor.href.replace( rhash, "" );
15335 locationUrl = location.href.replace( rhash, "" );
15337 // decoding may throw an error if the URL isn't UTF-8 (#9518)
15339 anchorUrl = decodeURIComponent( anchorUrl );
15340 } catch ( error ) {}
15342 locationUrl = decodeURIComponent( locationUrl );
15343 } catch ( error ) {}
15345 return anchor.hash.length > 1 && anchorUrl === locationUrl;
15349 _create: function() {
15351 options = this.options;
15353 this.running = false;
15356 .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" )
15357 .toggleClass( "ui-tabs-collapsible", options.collapsible );
15359 this._processTabs();
15360 options.active = this._initialActive();
15362 // Take disabling tabs via class attribute from HTML
15363 // into account and update option properly.
15364 if ( $.isArray( options.disabled ) ) {
15365 options.disabled = $.unique( options.disabled.concat(
15366 $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
15367 return that.tabs.index( li );
15372 // check for length avoids error when initializing empty list
15373 if ( this.options.active !== false && this.anchors.length ) {
15374 this.active = this._findActive( options.active );
15381 if ( this.active.length ) {
15382 this.load( options.active );
15386 _initialActive: function() {
15387 var active = this.options.active,
15388 collapsible = this.options.collapsible,
15389 locationHash = location.hash.substring( 1 );
15391 if ( active === null ) {
15392 // check the fragment identifier in the URL
15393 if ( locationHash ) {
15394 this.tabs.each(function( i, tab ) {
15395 if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
15402 // check for a tab marked active via a class
15403 if ( active === null ) {
15404 active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
15407 // no active tab, set to false
15408 if ( active === null || active === -1 ) {
15409 active = this.tabs.length ? 0 : false;
15413 // handle numbers: negative, out of range
15414 if ( active !== false ) {
15415 active = this.tabs.index( this.tabs.eq( active ) );
15416 if ( active === -1 ) {
15417 active = collapsible ? false : 0;
15421 // don't allow collapsible: false and active: false
15422 if ( !collapsible && active === false && this.anchors.length ) {
15429 _getCreateEventData: function() {
15432 panel: !this.active.length ? $() : this._getPanelForTab( this.active )
15436 _tabKeydown: function( event ) {
15437 var focusedTab = $( this.document[0].activeElement ).closest( "li" ),
15438 selectedIndex = this.tabs.index( focusedTab ),
15439 goingForward = true;
15441 if ( this._handlePageNav( event ) ) {
15445 switch ( event.keyCode ) {
15446 case $.ui.keyCode.RIGHT:
15447 case $.ui.keyCode.DOWN:
15450 case $.ui.keyCode.UP:
15451 case $.ui.keyCode.LEFT:
15452 goingForward = false;
15455 case $.ui.keyCode.END:
15456 selectedIndex = this.anchors.length - 1;
15458 case $.ui.keyCode.HOME:
15461 case $.ui.keyCode.SPACE:
15462 // Activate only, no collapsing
15463 event.preventDefault();
15464 clearTimeout( this.activating );
15465 this._activate( selectedIndex );
15467 case $.ui.keyCode.ENTER:
15468 // Toggle (cancel delayed activation, allow collapsing)
15469 event.preventDefault();
15470 clearTimeout( this.activating );
15471 // Determine if we should collapse or activate
15472 this._activate( selectedIndex === this.options.active ? false : selectedIndex );
15478 // Focus the appropriate tab, based on which key was pressed
15479 event.preventDefault();
15480 clearTimeout( this.activating );
15481 selectedIndex = this._focusNextTab( selectedIndex, goingForward );
15483 // Navigating with control/command key will prevent automatic activation
15484 if ( !event.ctrlKey && !event.metaKey ) {
15486 // Update aria-selected immediately so that AT think the tab is already selected.
15487 // Otherwise AT may confuse the user by stating that they need to activate the tab,
15488 // but the tab will already be activated by the time the announcement finishes.
15489 focusedTab.attr( "aria-selected", "false" );
15490 this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
15492 this.activating = this._delay(function() {
15493 this.option( "active", selectedIndex );
15498 _panelKeydown: function( event ) {
15499 if ( this._handlePageNav( event ) ) {
15503 // Ctrl+up moves focus to the current tab
15504 if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
15505 event.preventDefault();
15506 this.active.focus();
15510 // Alt+page up/down moves focus to the previous/next tab (and activates)
15511 _handlePageNav: function( event ) {
15512 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
15513 this._activate( this._focusNextTab( this.options.active - 1, false ) );
15516 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
15517 this._activate( this._focusNextTab( this.options.active + 1, true ) );
15522 _findNextTab: function( index, goingForward ) {
15523 var lastTabIndex = this.tabs.length - 1;
15525 function constrain() {
15526 if ( index > lastTabIndex ) {
15530 index = lastTabIndex;
15535 while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
15536 index = goingForward ? index + 1 : index - 1;
15542 _focusNextTab: function( index, goingForward ) {
15543 index = this._findNextTab( index, goingForward );
15544 this.tabs.eq( index ).focus();
15548 _setOption: function( key, value ) {
15549 if ( key === "active" ) {
15550 // _activate() will handle invalid values and update this.options
15551 this._activate( value );
15555 if ( key === "disabled" ) {
15556 // don't use the widget factory's disabled handling
15557 this._setupDisabled( value );
15561 this._super( key, value);
15563 if ( key === "collapsible" ) {
15564 this.element.toggleClass( "ui-tabs-collapsible", value );
15565 // Setting collapsible: false while collapsed; open first panel
15566 if ( !value && this.options.active === false ) {
15567 this._activate( 0 );
15571 if ( key === "event" ) {
15572 this._setupEvents( value );
15575 if ( key === "heightStyle" ) {
15576 this._setupHeightStyle( value );
15580 _sanitizeSelector: function( hash ) {
15581 return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
15584 refresh: function() {
15585 var options = this.options,
15586 lis = this.tablist.children( ":has(a[href])" );
15588 // get disabled tabs from class attribute from HTML
15589 // this will get converted to a boolean if needed in _refresh()
15590 options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
15591 return lis.index( tab );
15594 this._processTabs();
15596 // was collapsed or no tabs
15597 if ( options.active === false || !this.anchors.length ) {
15598 options.active = false;
15600 // was active, but active tab is gone
15601 } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
15602 // all remaining tabs are disabled
15603 if ( this.tabs.length === options.disabled.length ) {
15604 options.active = false;
15606 // activate previous tab
15608 this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
15610 // was active, active tab still exists
15612 // make sure active index is correct
15613 options.active = this.tabs.index( this.active );
15619 _refresh: function() {
15620 this._setupDisabled( this.options.disabled );
15621 this._setupEvents( this.options.event );
15622 this._setupHeightStyle( this.options.heightStyle );
15624 this.tabs.not( this.active ).attr({
15625 "aria-selected": "false",
15626 "aria-expanded": "false",
15629 this.panels.not( this._getPanelForTab( this.active ) )
15632 "aria-hidden": "true"
15635 // Make sure one tab is in the tab order
15636 if ( !this.active.length ) {
15637 this.tabs.eq( 0 ).attr( "tabIndex", 0 );
15640 .addClass( "ui-tabs-active ui-state-active" )
15642 "aria-selected": "true",
15643 "aria-expanded": "true",
15646 this._getPanelForTab( this.active )
15649 "aria-hidden": "false"
15654 _processTabs: function() {
15656 prevTabs = this.tabs,
15657 prevAnchors = this.anchors,
15658 prevPanels = this.panels;
15660 this.tablist = this._getList()
15661 .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
15662 .attr( "role", "tablist" )
15664 // Prevent users from focusing disabled tabs via click
15665 .delegate( "> li", "mousedown" + this.eventNamespace, function( event ) {
15666 if ( $( this ).is( ".ui-state-disabled" ) ) {
15667 event.preventDefault();
15672 // Preventing the default action in mousedown doesn't prevent IE
15673 // from focusing the element, so if the anchor gets focused, blur.
15674 // We don't have to worry about focusing the previously focused
15675 // element since clicking on a non-focusable element should focus
15676 // the body anyway.
15677 .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() {
15678 if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
15683 this.tabs = this.tablist.find( "> li:has(a[href])" )
15684 .addClass( "ui-state-default ui-corner-top" )
15690 this.anchors = this.tabs.map(function() {
15691 return $( "a", this )[ 0 ];
15693 .addClass( "ui-tabs-anchor" )
15695 role: "presentation",
15701 this.anchors.each(function( i, anchor ) {
15702 var selector, panel, panelId,
15703 anchorId = $( anchor ).uniqueId().attr( "id" ),
15704 tab = $( anchor ).closest( "li" ),
15705 originalAriaControls = tab.attr( "aria-controls" );
15708 if ( that._isLocal( anchor ) ) {
15709 selector = anchor.hash;
15710 panelId = selector.substring( 1 );
15711 panel = that.element.find( that._sanitizeSelector( selector ) );
15714 // If the tab doesn't already have aria-controls,
15715 // generate an id by using a throw-away element
15716 panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id;
15717 selector = "#" + panelId;
15718 panel = that.element.find( selector );
15719 if ( !panel.length ) {
15720 panel = that._createPanel( panelId );
15721 panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
15723 panel.attr( "aria-live", "polite" );
15726 if ( panel.length) {
15727 that.panels = that.panels.add( panel );
15729 if ( originalAriaControls ) {
15730 tab.data( "ui-tabs-aria-controls", originalAriaControls );
15733 "aria-controls": panelId,
15734 "aria-labelledby": anchorId
15736 panel.attr( "aria-labelledby", anchorId );
15740 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
15741 .attr( "role", "tabpanel" );
15743 // Avoid memory leaks (#10056)
15745 this._off( prevTabs.not( this.tabs ) );
15746 this._off( prevAnchors.not( this.anchors ) );
15747 this._off( prevPanels.not( this.panels ) );
15751 // allow overriding how to find the list for rare usage scenarios (#7715)
15752 _getList: function() {
15753 return this.tablist || this.element.find( "ol,ul" ).eq( 0 );
15756 _createPanel: function( id ) {
15757 return $( "<div>" )
15759 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
15760 .data( "ui-tabs-destroy", true );
15763 _setupDisabled: function( disabled ) {
15764 if ( $.isArray( disabled ) ) {
15765 if ( !disabled.length ) {
15767 } else if ( disabled.length === this.anchors.length ) {
15773 for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) {
15774 if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
15776 .addClass( "ui-state-disabled" )
15777 .attr( "aria-disabled", "true" );
15780 .removeClass( "ui-state-disabled" )
15781 .removeAttr( "aria-disabled" );
15785 this.options.disabled = disabled;
15788 _setupEvents: function( event ) {
15791 $.each( event.split(" "), function( index, eventName ) {
15792 events[ eventName ] = "_eventHandler";
15796 this._off( this.anchors.add( this.tabs ).add( this.panels ) );
15797 // Always prevent the default action, even when disabled
15798 this._on( true, this.anchors, {
15799 click: function( event ) {
15800 event.preventDefault();
15803 this._on( this.anchors, events );
15804 this._on( this.tabs, { keydown: "_tabKeydown" } );
15805 this._on( this.panels, { keydown: "_panelKeydown" } );
15807 this._focusable( this.tabs );
15808 this._hoverable( this.tabs );
15811 _setupHeightStyle: function( heightStyle ) {
15813 parent = this.element.parent();
15815 if ( heightStyle === "fill" ) {
15816 maxHeight = parent.height();
15817 maxHeight -= this.element.outerHeight() - this.element.height();
15819 this.element.siblings( ":visible" ).each(function() {
15820 var elem = $( this ),
15821 position = elem.css( "position" );
15823 if ( position === "absolute" || position === "fixed" ) {
15826 maxHeight -= elem.outerHeight( true );
15829 this.element.children().not( this.panels ).each(function() {
15830 maxHeight -= $( this ).outerHeight( true );
15833 this.panels.each(function() {
15834 $( this ).height( Math.max( 0, maxHeight -
15835 $( this ).innerHeight() + $( this ).height() ) );
15837 .css( "overflow", "auto" );
15838 } else if ( heightStyle === "auto" ) {
15840 this.panels.each(function() {
15841 maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
15842 }).height( maxHeight );
15846 _eventHandler: function( event ) {
15847 var options = this.options,
15848 active = this.active,
15849 anchor = $( event.currentTarget ),
15850 tab = anchor.closest( "li" ),
15851 clickedIsActive = tab[ 0 ] === active[ 0 ],
15852 collapsing = clickedIsActive && options.collapsible,
15853 toShow = collapsing ? $() : this._getPanelForTab( tab ),
15854 toHide = !active.length ? $() : this._getPanelForTab( active ),
15858 newTab: collapsing ? $() : tab,
15862 event.preventDefault();
15864 if ( tab.hasClass( "ui-state-disabled" ) ||
15865 // tab is already loading
15866 tab.hasClass( "ui-tabs-loading" ) ||
15867 // can't switch durning an animation
15869 // click on active header, but not collapsible
15870 ( clickedIsActive && !options.collapsible ) ||
15871 // allow canceling activation
15872 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
15876 options.active = collapsing ? false : this.tabs.index( tab );
15878 this.active = clickedIsActive ? $() : tab;
15883 if ( !toHide.length && !toShow.length ) {
15884 $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
15887 if ( toShow.length ) {
15888 this.load( this.tabs.index( tab ), event );
15890 this._toggle( event, eventData );
15893 // handles show/hide for selecting tabs
15894 _toggle: function( event, eventData ) {
15896 toShow = eventData.newPanel,
15897 toHide = eventData.oldPanel;
15899 this.running = true;
15901 function complete() {
15902 that.running = false;
15903 that._trigger( "activate", event, eventData );
15907 eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" );
15909 if ( toShow.length && that.options.show ) {
15910 that._show( toShow, that.options.show, complete );
15917 // start out by hiding, then showing, then completing
15918 if ( toHide.length && this.options.hide ) {
15919 this._hide( toHide, this.options.hide, function() {
15920 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
15924 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
15929 toHide.attr( "aria-hidden", "true" );
15930 eventData.oldTab.attr({
15931 "aria-selected": "false",
15932 "aria-expanded": "false"
15934 // If we're switching tabs, remove the old tab from the tab order.
15935 // If we're opening from collapsed state, remove the previous tab from the tab order.
15936 // If we're collapsing, then keep the collapsing tab in the tab order.
15937 if ( toShow.length && toHide.length ) {
15938 eventData.oldTab.attr( "tabIndex", -1 );
15939 } else if ( toShow.length ) {
15940 this.tabs.filter(function() {
15941 return $( this ).attr( "tabIndex" ) === 0;
15943 .attr( "tabIndex", -1 );
15946 toShow.attr( "aria-hidden", "false" );
15947 eventData.newTab.attr({
15948 "aria-selected": "true",
15949 "aria-expanded": "true",
15954 _activate: function( index ) {
15956 active = this._findActive( index );
15958 // trying to activate the already active panel
15959 if ( active[ 0 ] === this.active[ 0 ] ) {
15963 // trying to collapse, simulate a click on the current active header
15964 if ( !active.length ) {
15965 active = this.active;
15968 anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
15969 this._eventHandler({
15971 currentTarget: anchor,
15972 preventDefault: $.noop
15976 _findActive: function( index ) {
15977 return index === false ? $() : this.tabs.eq( index );
15980 _getIndex: function( index ) {
15981 // meta-function to give users option to provide a href string instead of a numerical index.
15982 if ( typeof index === "string" ) {
15983 index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) );
15989 _destroy: function() {
15994 this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" );
15997 .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
15998 .removeAttr( "role" );
16001 .removeClass( "ui-tabs-anchor" )
16002 .removeAttr( "role" )
16003 .removeAttr( "tabIndex" )
16006 this.tablist.unbind( this.eventNamespace );
16008 this.tabs.add( this.panels ).each(function() {
16009 if ( $.data( this, "ui-tabs-destroy" ) ) {
16010 $( this ).remove();
16013 .removeClass( "ui-state-default ui-state-active ui-state-disabled " +
16014 "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" )
16015 .removeAttr( "tabIndex" )
16016 .removeAttr( "aria-live" )
16017 .removeAttr( "aria-busy" )
16018 .removeAttr( "aria-selected" )
16019 .removeAttr( "aria-labelledby" )
16020 .removeAttr( "aria-hidden" )
16021 .removeAttr( "aria-expanded" )
16022 .removeAttr( "role" );
16026 this.tabs.each(function() {
16027 var li = $( this ),
16028 prev = li.data( "ui-tabs-aria-controls" );
16031 .attr( "aria-controls", prev )
16032 .removeData( "ui-tabs-aria-controls" );
16034 li.removeAttr( "aria-controls" );
16038 this.panels.show();
16040 if ( this.options.heightStyle !== "content" ) {
16041 this.panels.css( "height", "" );
16045 enable: function( index ) {
16046 var disabled = this.options.disabled;
16047 if ( disabled === false ) {
16051 if ( index === undefined ) {
16054 index = this._getIndex( index );
16055 if ( $.isArray( disabled ) ) {
16056 disabled = $.map( disabled, function( num ) {
16057 return num !== index ? num : null;
16060 disabled = $.map( this.tabs, function( li, num ) {
16061 return num !== index ? num : null;
16065 this._setupDisabled( disabled );
16068 disable: function( index ) {
16069 var disabled = this.options.disabled;
16070 if ( disabled === true ) {
16074 if ( index === undefined ) {
16077 index = this._getIndex( index );
16078 if ( $.inArray( index, disabled ) !== -1 ) {
16081 if ( $.isArray( disabled ) ) {
16082 disabled = $.merge( [ index ], disabled ).sort();
16084 disabled = [ index ];
16087 this._setupDisabled( disabled );
16090 load: function( index, event ) {
16091 index = this._getIndex( index );
16093 tab = this.tabs.eq( index ),
16094 anchor = tab.find( ".ui-tabs-anchor" ),
16095 panel = this._getPanelForTab( tab ),
16102 if ( this._isLocal( anchor[ 0 ] ) ) {
16106 this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
16108 // support: jQuery <1.8
16109 // jQuery <1.8 returns false if the request is canceled in beforeSend,
16110 // but as of 1.8, $.ajax() always returns a jqXHR object.
16111 if ( this.xhr && this.xhr.statusText !== "canceled" ) {
16112 tab.addClass( "ui-tabs-loading" );
16113 panel.attr( "aria-busy", "true" );
16116 .success(function( response ) {
16117 // support: jQuery <1.8
16118 // http://bugs.jquery.com/ticket/11778
16119 setTimeout(function() {
16120 panel.html( response );
16121 that._trigger( "load", event, eventData );
16124 .complete(function( jqXHR, status ) {
16125 // support: jQuery <1.8
16126 // http://bugs.jquery.com/ticket/11778
16127 setTimeout(function() {
16128 if ( status === "abort" ) {
16129 that.panels.stop( false, true );
16132 tab.removeClass( "ui-tabs-loading" );
16133 panel.removeAttr( "aria-busy" );
16135 if ( jqXHR === that.xhr ) {
16143 _ajaxSettings: function( anchor, event, eventData ) {
16146 url: anchor.attr( "href" ),
16147 beforeSend: function( jqXHR, settings ) {
16148 return that._trigger( "beforeLoad", event,
16149 $.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) );
16154 _getPanelForTab: function( tab ) {
16155 var id = $( tab ).attr( "aria-controls" );
16156 return this.element.find( this._sanitizeSelector( "#" + id ) );
16162 * jQuery UI Tooltip 1.11.3
16163 * http://jqueryui.com
16165 * Copyright jQuery Foundation and other contributors
16166 * Released under the MIT license.
16167 * http://jquery.org/license
16169 * http://api.jqueryui.com/tooltip/
16173 var tooltip = $.widget( "ui.tooltip", {
16176 content: function() {
16177 // support: IE<9, Opera in jQuery <1.7
16178 // .text() can't accept undefined, so coerce to a string
16179 var title = $( this ).attr( "title" ) || "";
16180 // Escape title, since we're going from an attribute to raw HTML
16181 return $( "<a>" ).text( title ).html();
16184 // Disabled elements have inconsistent behavior across browsers (#8661)
16185 items: "[title]:not([disabled])",
16189 collision: "flipfit flip"
16192 tooltipClass: null,
16200 _addDescribedBy: function( elem, id ) {
16201 var describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ );
16202 describedby.push( id );
16204 .data( "ui-tooltip-id", id )
16205 .attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
16208 _removeDescribedBy: function( elem ) {
16209 var id = elem.data( "ui-tooltip-id" ),
16210 describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ),
16211 index = $.inArray( id, describedby );
16213 if ( index !== -1 ) {
16214 describedby.splice( index, 1 );
16217 elem.removeData( "ui-tooltip-id" );
16218 describedby = $.trim( describedby.join( " " ) );
16219 if ( describedby ) {
16220 elem.attr( "aria-describedby", describedby );
16222 elem.removeAttr( "aria-describedby" );
16226 _create: function() {
16232 // IDs of generated tooltips, needed for destroy
16233 this.tooltips = {};
16235 // IDs of parent tooltips where we removed the title attribute
16238 if ( this.options.disabled ) {
16242 // Append the aria-live region so tooltips announce correctly
16243 this.liveRegion = $( "<div>" )
16246 "aria-live": "assertive",
16247 "aria-relevant": "additions"
16249 .addClass( "ui-helper-hidden-accessible" )
16250 .appendTo( this.document[ 0 ].body );
16253 _setOption: function( key, value ) {
16256 if ( key === "disabled" ) {
16257 this[ value ? "_disable" : "_enable" ]();
16258 this.options[ key ] = value;
16259 // disable element style changes
16263 this._super( key, value );
16265 if ( key === "content" ) {
16266 $.each( this.tooltips, function( id, tooltipData ) {
16267 that._updateContent( tooltipData.element );
16272 _disable: function() {
16275 // close open tooltips
16276 $.each( this.tooltips, function( id, tooltipData ) {
16277 var event = $.Event( "blur" );
16278 event.target = event.currentTarget = tooltipData.element[ 0 ];
16279 that.close( event, true );
16282 // remove title attributes to prevent native tooltips
16283 this.element.find( this.options.items ).addBack().each(function() {
16284 var element = $( this );
16285 if ( element.is( "[title]" ) ) {
16287 .data( "ui-tooltip-title", element.attr( "title" ) )
16288 .removeAttr( "title" );
16293 _enable: function() {
16294 // restore title attributes
16295 this.element.find( this.options.items ).addBack().each(function() {
16296 var element = $( this );
16297 if ( element.data( "ui-tooltip-title" ) ) {
16298 element.attr( "title", element.data( "ui-tooltip-title" ) );
16303 open: function( event ) {
16305 target = $( event ? event.target : this.element )
16306 // we need closest here due to mouseover bubbling,
16307 // but always pointing at the same event target
16308 .closest( this.options.items );
16310 // No element to show a tooltip for or the tooltip is already open
16311 if ( !target.length || target.data( "ui-tooltip-id" ) ) {
16315 if ( target.attr( "title" ) ) {
16316 target.data( "ui-tooltip-title", target.attr( "title" ) );
16319 target.data( "ui-tooltip-open", true );
16321 // kill parent tooltips, custom or native, for hover
16322 if ( event && event.type === "mouseover" ) {
16323 target.parents().each(function() {
16324 var parent = $( this ),
16326 if ( parent.data( "ui-tooltip-open" ) ) {
16327 blurEvent = $.Event( "blur" );
16328 blurEvent.target = blurEvent.currentTarget = this;
16329 that.close( blurEvent, true );
16331 if ( parent.attr( "title" ) ) {
16333 that.parents[ this.id ] = {
16335 title: parent.attr( "title" )
16337 parent.attr( "title", "" );
16342 this._updateContent( target, event );
16345 _updateContent: function( target, event ) {
16347 contentOption = this.options.content,
16349 eventType = event ? event.type : null;
16351 if ( typeof contentOption === "string" ) {
16352 return this._open( event, target, contentOption );
16355 content = contentOption.call( target[0], function( response ) {
16356 // ignore async response if tooltip was closed already
16357 if ( !target.data( "ui-tooltip-open" ) ) {
16360 // IE may instantly serve a cached response for ajax requests
16361 // delay this call to _open so the other call to _open runs first
16362 that._delay(function() {
16363 // jQuery creates a special event for focusin when it doesn't
16364 // exist natively. To improve performance, the native event
16365 // object is reused and the type is changed. Therefore, we can't
16366 // rely on the type being correct after the event finished
16367 // bubbling, so we set it back to the previous value. (#8740)
16369 event.type = eventType;
16371 this._open( event, target, response );
16375 this._open( event, target, content );
16379 _open: function( event, target, content ) {
16380 var tooltipData, tooltip, events, delayedShow, a11yContent,
16381 positionOption = $.extend( {}, this.options.position );
16387 // Content can be updated multiple times. If the tooltip already
16388 // exists, then just update the content and bail.
16389 tooltipData = this._find( target );
16390 if ( tooltipData ) {
16391 tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content );
16395 // if we have a title, clear it to prevent the native tooltip
16396 // we have to check first to avoid defining a title if none exists
16397 // (we don't want to cause an element to start matching [title])
16399 // We use removeAttr only for key events, to allow IE to export the correct
16400 // accessible attributes. For mouse events, set to empty string to avoid
16401 // native tooltip showing up (happens only when removing inside mouseover).
16402 if ( target.is( "[title]" ) ) {
16403 if ( event && event.type === "mouseover" ) {
16404 target.attr( "title", "" );
16406 target.removeAttr( "title" );
16410 tooltipData = this._tooltip( target );
16411 tooltip = tooltipData.tooltip;
16412 this._addDescribedBy( target, tooltip.attr( "id" ) );
16413 tooltip.find( ".ui-tooltip-content" ).html( content );
16415 // Support: Voiceover on OS X, JAWS on IE <= 9
16416 // JAWS announces deletions even when aria-relevant="additions"
16417 // Voiceover will sometimes re-read the entire log region's contents from the beginning
16418 this.liveRegion.children().hide();
16419 if ( content.clone ) {
16420 a11yContent = content.clone();
16421 a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" );
16423 a11yContent = content;
16425 $( "<div>" ).html( a11yContent ).appendTo( this.liveRegion );
16427 function position( event ) {
16428 positionOption.of = event;
16429 if ( tooltip.is( ":hidden" ) ) {
16432 tooltip.position( positionOption );
16434 if ( this.options.track && event && /^mouse/.test( event.type ) ) {
16435 this._on( this.document, {
16436 mousemove: position
16438 // trigger once to override element-relative positioning
16441 tooltip.position( $.extend({
16443 }, this.options.position ) );
16448 this._show( tooltip, this.options.show );
16449 // Handle tracking tooltips that are shown with a delay (#8644). As soon
16450 // as the tooltip is visible, position the tooltip using the most recent
16452 if ( this.options.show && this.options.show.delay ) {
16453 delayedShow = this.delayedShow = setInterval(function() {
16454 if ( tooltip.is( ":visible" ) ) {
16455 position( positionOption.of );
16456 clearInterval( delayedShow );
16458 }, $.fx.interval );
16461 this._trigger( "open", event, { tooltip: tooltip } );
16464 keyup: function( event ) {
16465 if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
16466 var fakeEvent = $.Event(event);
16467 fakeEvent.currentTarget = target[0];
16468 this.close( fakeEvent, true );
16473 // Only bind remove handler for delegated targets. Non-delegated
16474 // tooltips will handle this in destroy.
16475 if ( target[ 0 ] !== this.element[ 0 ] ) {
16476 events.remove = function() {
16477 this._removeTooltip( tooltip );
16481 if ( !event || event.type === "mouseover" ) {
16482 events.mouseleave = "close";
16484 if ( !event || event.type === "focusin" ) {
16485 events.focusout = "close";
16487 this._on( true, target, events );
16490 close: function( event ) {
16493 target = $( event ? event.currentTarget : this.element ),
16494 tooltipData = this._find( target );
16496 // The tooltip may already be closed
16497 if ( !tooltipData ) {
16501 tooltip = tooltipData.tooltip;
16503 // disabling closes the tooltip, so we need to track when we're closing
16504 // to avoid an infinite loop in case the tooltip becomes disabled on close
16505 if ( tooltipData.closing ) {
16509 // Clear the interval for delayed tracking tooltips
16510 clearInterval( this.delayedShow );
16512 // only set title if we had one before (see comment in _open())
16513 // If the title attribute has changed since open(), don't restore
16514 if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) {
16515 target.attr( "title", target.data( "ui-tooltip-title" ) );
16518 this._removeDescribedBy( target );
16520 tooltipData.hiding = true;
16521 tooltip.stop( true );
16522 this._hide( tooltip, this.options.hide, function() {
16523 that._removeTooltip( $( this ) );
16526 target.removeData( "ui-tooltip-open" );
16527 this._off( target, "mouseleave focusout keyup" );
16529 // Remove 'remove' binding only on delegated targets
16530 if ( target[ 0 ] !== this.element[ 0 ] ) {
16531 this._off( target, "remove" );
16533 this._off( this.document, "mousemove" );
16535 if ( event && event.type === "mouseleave" ) {
16536 $.each( this.parents, function( id, parent ) {
16537 $( parent.element ).attr( "title", parent.title );
16538 delete that.parents[ id ];
16542 tooltipData.closing = true;
16543 this._trigger( "close", event, { tooltip: tooltip } );
16544 if ( !tooltipData.hiding ) {
16545 tooltipData.closing = false;
16549 _tooltip: function( element ) {
16550 var tooltip = $( "<div>" )
16551 .attr( "role", "tooltip" )
16552 .addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " +
16553 ( this.options.tooltipClass || "" ) ),
16554 id = tooltip.uniqueId().attr( "id" );
16557 .addClass( "ui-tooltip-content" )
16558 .appendTo( tooltip );
16560 tooltip.appendTo( this.document[0].body );
16562 return this.tooltips[ id ] = {
16568 _find: function( target ) {
16569 var id = target.data( "ui-tooltip-id" );
16570 return id ? this.tooltips[ id ] : null;
16573 _removeTooltip: function( tooltip ) {
16575 delete this.tooltips[ tooltip.attr( "id" ) ];
16578 _destroy: function() {
16581 // close open tooltips
16582 $.each( this.tooltips, function( id, tooltipData ) {
16583 // Delegate to close method to handle common cleanup
16584 var event = $.Event( "blur" ),
16585 element = tooltipData.element;
16586 event.target = event.currentTarget = element[ 0 ];
16587 that.close( event, true );
16589 // Remove immediately; destroying an open tooltip doesn't use the
16591 $( "#" + id ).remove();
16593 // Restore the title
16594 if ( element.data( "ui-tooltip-title" ) ) {
16595 // If the title attribute has changed since open(), don't restore
16596 if ( !element.attr( "title" ) ) {
16597 element.attr( "title", element.data( "ui-tooltip-title" ) );
16599 element.removeData( "ui-tooltip-title" );
16602 this.liveRegion.remove();