1 /*! jQuery UI - v1.11.4 - 2015-03-11
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 2015 jQuery Foundation and other contributors; Licensed MIT */
7 if ( typeof define === "function" && define.amd ) {
9 // AMD. Register as an anonymous module.
10 define([ "jquery" ], factory );
18 * jQuery UI Core 1.11.4
21 * Copyright jQuery Foundation and other contributors
22 * Released under the MIT license.
23 * http://jquery.org/license
25 * http://api.jqueryui.com/category/ui-core/
29 // $.ui might exist from components with no dependencies, e.g., $.ui.position
57 scrollParent: function( includeHidden ) {
58 var position = this.css( "position" ),
59 excludeStaticParent = position === "absolute",
60 overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/,
61 scrollParent = this.parents().filter( function() {
62 var parent = $( this );
63 if ( excludeStaticParent && parent.css( "position" ) === "static" ) {
66 return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) + parent.css( "overflow-x" ) );
69 return position === "fixed" || !scrollParent.length ? $( this[ 0 ].ownerDocument || document ) : scrollParent;
72 uniqueId: (function() {
76 return this.each(function() {
78 this.id = "ui-id-" + ( ++uuid );
84 removeUniqueId: function() {
85 return this.each(function() {
86 if ( /^ui-id-\d+$/.test( this.id ) ) {
87 $( this ).removeAttr( "id" );
94 function focusable( element, isTabIndexNotNaN ) {
95 var map, mapName, img,
96 nodeName = element.nodeName.toLowerCase();
97 if ( "area" === nodeName ) {
98 map = element.parentNode;
100 if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
103 img = $( "img[usemap='#" + mapName + "']" )[ 0 ];
104 return !!img && visible( img );
106 return ( /^(input|select|textarea|button|object)$/.test( nodeName ) ?
109 element.href || isTabIndexNotNaN :
111 // the element and all of its ancestors must be visible
115 function visible( element ) {
116 return $.expr.filters.visible( element ) &&
117 !$( element ).parents().addBack().filter(function() {
118 return $.css( this, "visibility" ) === "hidden";
122 $.extend( $.expr[ ":" ], {
123 data: $.expr.createPseudo ?
124 $.expr.createPseudo(function( dataName ) {
125 return function( elem ) {
126 return !!$.data( elem, dataName );
129 // support: jQuery <1.8
130 function( elem, i, match ) {
131 return !!$.data( elem, match[ 3 ] );
134 focusable: function( element ) {
135 return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) );
138 tabbable: function( element ) {
139 var tabIndex = $.attr( element, "tabindex" ),
140 isTabIndexNaN = isNaN( tabIndex );
141 return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN );
145 // support: jQuery <1.8
146 if ( !$( "<a>" ).outerWidth( 1 ).jquery ) {
147 $.each( [ "Width", "Height" ], function( i, name ) {
148 var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
149 type = name.toLowerCase(),
151 innerWidth: $.fn.innerWidth,
152 innerHeight: $.fn.innerHeight,
153 outerWidth: $.fn.outerWidth,
154 outerHeight: $.fn.outerHeight
157 function reduce( elem, size, border, margin ) {
158 $.each( side, function() {
159 size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
161 size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
164 size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
170 $.fn[ "inner" + name ] = function( size ) {
171 if ( size === undefined ) {
172 return orig[ "inner" + name ].call( this );
175 return this.each(function() {
176 $( this ).css( type, reduce( this, size ) + "px" );
180 $.fn[ "outer" + name] = function( size, margin ) {
181 if ( typeof size !== "number" ) {
182 return orig[ "outer" + name ].call( this, size );
185 return this.each(function() {
186 $( this).css( type, reduce( this, size, true, margin ) + "px" );
192 // support: jQuery <1.8
193 if ( !$.fn.addBack ) {
194 $.fn.addBack = function( selector ) {
195 return this.add( selector == null ?
196 this.prevObject : this.prevObject.filter( selector )
201 // support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413)
202 if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) {
203 $.fn.removeData = (function( removeData ) {
204 return function( key ) {
205 if ( arguments.length ) {
206 return removeData.call( this, $.camelCase( key ) );
208 return removeData.call( this );
211 })( $.fn.removeData );
215 $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
218 focus: (function( orig ) {
219 return function( delay, fn ) {
220 return typeof delay === "number" ?
221 this.each(function() {
223 setTimeout(function() {
230 orig.apply( this, arguments );
234 disableSelection: (function() {
235 var eventType = "onselectstart" in document.createElement( "div" ) ?
240 return this.bind( eventType + ".ui-disableSelection", function( event ) {
241 event.preventDefault();
246 enableSelection: function() {
247 return this.unbind( ".ui-disableSelection" );
250 zIndex: function( zIndex ) {
251 if ( zIndex !== undefined ) {
252 return this.css( "zIndex", zIndex );
256 var elem = $( this[ 0 ] ), position, value;
257 while ( elem.length && elem[ 0 ] !== document ) {
258 // Ignore z-index if position is set to a value where z-index is ignored by the browser
259 // This makes behavior of this function consistent across browsers
260 // WebKit always returns auto if the element is positioned
261 position = elem.css( "position" );
262 if ( position === "absolute" || position === "relative" || position === "fixed" ) {
263 // IE returns 0 when zIndex is not specified
264 // other browsers return a string
265 // we ignore the case of nested elements with an explicit value of 0
266 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
267 value = parseInt( elem.css( "zIndex" ), 10 );
268 if ( !isNaN( value ) && value !== 0 ) {
272 elem = elem.parent();
280 // $.ui.plugin is deprecated. Use $.widget() extensions instead.
282 add: function( module, option, set ) {
284 proto = $.ui[ module ].prototype;
286 proto.plugins[ i ] = proto.plugins[ i ] || [];
287 proto.plugins[ i ].push( [ option, set[ i ] ] );
290 call: function( instance, name, args, allowDisconnected ) {
292 set = instance.plugins[ name ];
298 if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) ) {
302 for ( i = 0; i < set.length; i++ ) {
303 if ( instance.options[ set[ i ][ 0 ] ] ) {
304 set[ i ][ 1 ].apply( instance.element, args );
312 * jQuery UI Widget 1.11.4
313 * http://jqueryui.com
315 * Copyright jQuery Foundation and other contributors
316 * Released under the MIT license.
317 * http://jquery.org/license
319 * http://api.jqueryui.com/jQuery.widget/
324 widget_slice = Array.prototype.slice;
326 $.cleanData = (function( orig ) {
327 return function( elems ) {
329 for ( i = 0; (elem = elems[i]) != null; i++ ) {
332 // Only trigger remove when necessary to save time
333 events = $._data( elem, "events" );
334 if ( events && events.remove ) {
335 $( elem ).triggerHandler( "remove" );
338 // http://bugs.jquery.com/ticket/8235
345 $.widget = function( name, base, prototype ) {
346 var fullName, existingConstructor, constructor, basePrototype,
347 // proxiedPrototype allows the provided prototype to remain unmodified
348 // so that it can be used as a mixin for multiple widgets (#8876)
349 proxiedPrototype = {},
350 namespace = name.split( "." )[ 0 ];
352 name = name.split( "." )[ 1 ];
353 fullName = namespace + "-" + name;
360 // create selector for plugin
361 $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
362 return !!$.data( elem, fullName );
365 $[ namespace ] = $[ namespace ] || {};
366 existingConstructor = $[ namespace ][ name ];
367 constructor = $[ namespace ][ name ] = function( options, element ) {
368 // allow instantiation without "new" keyword
369 if ( !this._createWidget ) {
370 return new constructor( options, element );
373 // allow instantiation without initializing for simple inheritance
374 // must use "new" keyword (the code above always passes args)
375 if ( arguments.length ) {
376 this._createWidget( options, element );
379 // extend with the existing constructor to carry over any static properties
380 $.extend( constructor, existingConstructor, {
381 version: prototype.version,
382 // copy the object used to create the prototype in case we need to
383 // redefine the widget later
384 _proto: $.extend( {}, prototype ),
385 // track widgets that inherit from this widget in case this widget is
386 // redefined after a widget inherits from it
387 _childConstructors: []
390 basePrototype = new base();
391 // we need to make the options hash a property directly on the new instance
392 // otherwise we'll modify the options hash on the prototype that we're
394 basePrototype.options = $.widget.extend( {}, basePrototype.options );
395 $.each( prototype, function( prop, value ) {
396 if ( !$.isFunction( value ) ) {
397 proxiedPrototype[ prop ] = value;
400 proxiedPrototype[ prop ] = (function() {
401 var _super = function() {
402 return base.prototype[ prop ].apply( this, arguments );
404 _superApply = function( args ) {
405 return base.prototype[ prop ].apply( this, args );
408 var __super = this._super,
409 __superApply = this._superApply,
412 this._super = _super;
413 this._superApply = _superApply;
415 returnValue = value.apply( this, arguments );
417 this._super = __super;
418 this._superApply = __superApply;
424 constructor.prototype = $.widget.extend( basePrototype, {
425 // TODO: remove support for widgetEventPrefix
426 // always use the name + a colon as the prefix, e.g., draggable:start
427 // don't prefix for widgets that aren't DOM-based
428 widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name
429 }, proxiedPrototype, {
430 constructor: constructor,
431 namespace: namespace,
433 widgetFullName: fullName
436 // If this widget is being redefined then we need to find all widgets that
437 // are inheriting from it and redefine all of them so that they inherit from
438 // the new version of this widget. We're essentially trying to replace one
439 // level in the prototype chain.
440 if ( existingConstructor ) {
441 $.each( existingConstructor._childConstructors, function( i, child ) {
442 var childPrototype = child.prototype;
444 // redefine the child widget using the same prototype that was
445 // originally used, but inherit from the new version of the base
446 $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
448 // remove the list of existing child constructors from the old constructor
449 // so the old child constructors can be garbage collected
450 delete existingConstructor._childConstructors;
452 base._childConstructors.push( constructor );
455 $.widget.bridge( name, constructor );
460 $.widget.extend = function( target ) {
461 var input = widget_slice.call( arguments, 1 ),
463 inputLength = input.length,
466 for ( ; inputIndex < inputLength; inputIndex++ ) {
467 for ( key in input[ inputIndex ] ) {
468 value = input[ inputIndex ][ key ];
469 if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
471 if ( $.isPlainObject( value ) ) {
472 target[ key ] = $.isPlainObject( target[ key ] ) ?
473 $.widget.extend( {}, target[ key ], value ) :
474 // Don't extend strings, arrays, etc. with objects
475 $.widget.extend( {}, value );
476 // Copy everything else by reference
478 target[ key ] = value;
486 $.widget.bridge = function( name, object ) {
487 var fullName = object.prototype.widgetFullName || name;
488 $.fn[ name ] = function( options ) {
489 var isMethodCall = typeof options === "string",
490 args = widget_slice.call( arguments, 1 ),
493 if ( isMethodCall ) {
494 this.each(function() {
496 instance = $.data( this, fullName );
497 if ( options === "instance" ) {
498 returnValue = instance;
502 return $.error( "cannot call methods on " + name + " prior to initialization; " +
503 "attempted to call method '" + options + "'" );
505 if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
506 return $.error( "no such method '" + options + "' for " + name + " widget instance" );
508 methodValue = instance[ options ].apply( instance, args );
509 if ( methodValue !== instance && methodValue !== undefined ) {
510 returnValue = methodValue && methodValue.jquery ?
511 returnValue.pushStack( methodValue.get() ) :
518 // Allow multiple hashes to be passed on init
520 options = $.widget.extend.apply( null, [ options ].concat(args) );
523 this.each(function() {
524 var instance = $.data( this, fullName );
526 instance.option( options || {} );
527 if ( instance._init ) {
531 $.data( this, fullName, new object( options, this ) );
540 $.Widget = function( /* options, element */ ) {};
541 $.Widget._childConstructors = [];
543 $.Widget.prototype = {
544 widgetName: "widget",
545 widgetEventPrefix: "",
546 defaultElement: "<div>",
553 _createWidget: function( options, element ) {
554 element = $( element || this.defaultElement || this )[ 0 ];
555 this.element = $( element );
556 this.uuid = widget_uuid++;
557 this.eventNamespace = "." + this.widgetName + this.uuid;
560 this.hoverable = $();
561 this.focusable = $();
563 if ( element !== this ) {
564 $.data( element, this.widgetFullName, this );
565 this._on( true, this.element, {
566 remove: function( event ) {
567 if ( event.target === element ) {
572 this.document = $( element.style ?
573 // element within the document
574 element.ownerDocument :
575 // element is window or document
576 element.document || element );
577 this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
580 this.options = $.widget.extend( {},
582 this._getCreateOptions(),
586 this._trigger( "create", null, this._getCreateEventData() );
589 _getCreateOptions: $.noop,
590 _getCreateEventData: $.noop,
594 destroy: function() {
596 // we can probably remove the unbind calls in 2.0
597 // all event bindings should go through this._on()
599 .unbind( this.eventNamespace )
600 .removeData( this.widgetFullName )
601 // support: jquery <1.6.3
602 // http://bugs.jquery.com/ticket/9413
603 .removeData( $.camelCase( this.widgetFullName ) );
605 .unbind( this.eventNamespace )
606 .removeAttr( "aria-disabled" )
608 this.widgetFullName + "-disabled " +
609 "ui-state-disabled" );
611 // clean up events and states
612 this.bindings.unbind( this.eventNamespace );
613 this.hoverable.removeClass( "ui-state-hover" );
614 this.focusable.removeClass( "ui-state-focus" );
622 option: function( key, value ) {
628 if ( arguments.length === 0 ) {
629 // don't return a reference to the internal hash
630 return $.widget.extend( {}, this.options );
633 if ( typeof key === "string" ) {
634 // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
636 parts = key.split( "." );
638 if ( parts.length ) {
639 curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
640 for ( i = 0; i < parts.length - 1; i++ ) {
641 curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
642 curOption = curOption[ parts[ i ] ];
645 if ( arguments.length === 1 ) {
646 return curOption[ key ] === undefined ? null : curOption[ key ];
648 curOption[ key ] = value;
650 if ( arguments.length === 1 ) {
651 return this.options[ key ] === undefined ? null : this.options[ key ];
653 options[ key ] = value;
657 this._setOptions( options );
661 _setOptions: function( options ) {
664 for ( key in options ) {
665 this._setOption( key, options[ key ] );
670 _setOption: function( key, value ) {
671 this.options[ key ] = value;
673 if ( key === "disabled" ) {
675 .toggleClass( this.widgetFullName + "-disabled", !!value );
677 // If the widget is becoming disabled, then nothing is interactive
679 this.hoverable.removeClass( "ui-state-hover" );
680 this.focusable.removeClass( "ui-state-focus" );
688 return this._setOptions({ disabled: false });
690 disable: function() {
691 return this._setOptions({ disabled: true });
694 _on: function( suppressDisabledCheck, element, handlers ) {
698 // no suppressDisabledCheck flag, shuffle arguments
699 if ( typeof suppressDisabledCheck !== "boolean" ) {
701 element = suppressDisabledCheck;
702 suppressDisabledCheck = false;
705 // no element argument, shuffle and use this.element
708 element = this.element;
709 delegateElement = this.widget();
711 element = delegateElement = $( element );
712 this.bindings = this.bindings.add( element );
715 $.each( handlers, function( event, handler ) {
716 function handlerProxy() {
717 // allow widgets to customize the disabled handling
718 // - disabled as an array instead of boolean
719 // - disabled class as method for disabling individual parts
720 if ( !suppressDisabledCheck &&
721 ( instance.options.disabled === true ||
722 $( this ).hasClass( "ui-state-disabled" ) ) ) {
725 return ( typeof handler === "string" ? instance[ handler ] : handler )
726 .apply( instance, arguments );
729 // copy the guid so direct unbinding works
730 if ( typeof handler !== "string" ) {
731 handlerProxy.guid = handler.guid =
732 handler.guid || handlerProxy.guid || $.guid++;
735 var match = event.match( /^([\w:-]*)\s*(.*)$/ ),
736 eventName = match[1] + instance.eventNamespace,
739 delegateElement.delegate( selector, eventName, handlerProxy );
741 element.bind( eventName, handlerProxy );
746 _off: function( element, eventName ) {
747 eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) +
749 element.unbind( eventName ).undelegate( eventName );
751 // Clear the stack to avoid memory leaks (#10056)
752 this.bindings = $( this.bindings.not( element ).get() );
753 this.focusable = $( this.focusable.not( element ).get() );
754 this.hoverable = $( this.hoverable.not( element ).get() );
757 _delay: function( handler, delay ) {
758 function handlerProxy() {
759 return ( typeof handler === "string" ? instance[ handler ] : handler )
760 .apply( instance, arguments );
763 return setTimeout( handlerProxy, delay || 0 );
766 _hoverable: function( element ) {
767 this.hoverable = this.hoverable.add( element );
769 mouseenter: function( event ) {
770 $( event.currentTarget ).addClass( "ui-state-hover" );
772 mouseleave: function( event ) {
773 $( event.currentTarget ).removeClass( "ui-state-hover" );
778 _focusable: function( element ) {
779 this.focusable = this.focusable.add( element );
781 focusin: function( event ) {
782 $( event.currentTarget ).addClass( "ui-state-focus" );
784 focusout: function( event ) {
785 $( event.currentTarget ).removeClass( "ui-state-focus" );
790 _trigger: function( type, event, data ) {
792 callback = this.options[ type ];
795 event = $.Event( event );
796 event.type = ( type === this.widgetEventPrefix ?
798 this.widgetEventPrefix + type ).toLowerCase();
799 // the original event may come from any element
800 // so we need to reset the target on the new event
801 event.target = this.element[ 0 ];
803 // copy original event properties over to the new event
804 orig = event.originalEvent;
806 for ( prop in orig ) {
807 if ( !( prop in event ) ) {
808 event[ prop ] = orig[ prop ];
813 this.element.trigger( event, data );
814 return !( $.isFunction( callback ) &&
815 callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
816 event.isDefaultPrevented() );
820 $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
821 $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
822 if ( typeof options === "string" ) {
823 options = { effect: options };
826 effectName = !options ?
828 options === true || typeof options === "number" ?
830 options.effect || defaultEffect;
831 options = options || {};
832 if ( typeof options === "number" ) {
833 options = { duration: options };
835 hasOptions = !$.isEmptyObject( options );
836 options.complete = callback;
837 if ( options.delay ) {
838 element.delay( options.delay );
840 if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
841 element[ method ]( options );
842 } else if ( effectName !== method && element[ effectName ] ) {
843 element[ effectName ]( options.duration, options.easing, callback );
845 element.queue(function( next ) {
846 $( this )[ method ]();
848 callback.call( element[ 0 ] );
856 var widget = $.widget;
860 * jQuery UI Mouse 1.11.4
861 * http://jqueryui.com
863 * Copyright jQuery Foundation and other contributors
864 * Released under the MIT license.
865 * http://jquery.org/license
867 * http://api.jqueryui.com/mouse/
871 var mouseHandled = false;
872 $( document ).mouseup( function() {
873 mouseHandled = false;
876 var mouse = $.widget("ui.mouse", {
879 cancel: "input,textarea,button,select,option",
883 _mouseInit: function() {
887 .bind("mousedown." + this.widgetName, function(event) {
888 return that._mouseDown(event);
890 .bind("click." + this.widgetName, function(event) {
891 if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) {
892 $.removeData(event.target, that.widgetName + ".preventClickEvent");
893 event.stopImmediatePropagation();
898 this.started = false;
901 // TODO: make sure destroying one instance of mouse doesn't mess with
902 // other instances of mouse
903 _mouseDestroy: function() {
904 this.element.unbind("." + this.widgetName);
905 if ( this._mouseMoveDelegate ) {
907 .unbind("mousemove." + this.widgetName, this._mouseMoveDelegate)
908 .unbind("mouseup." + this.widgetName, this._mouseUpDelegate);
912 _mouseDown: function(event) {
913 // don't let more than one widget handle mouseStart
914 if ( mouseHandled ) {
918 this._mouseMoved = false;
920 // we may have missed mouseup (out of window)
921 (this._mouseStarted && this._mouseUp(event));
923 this._mouseDownEvent = event;
926 btnIsLeft = (event.which === 1),
927 // event.target.nodeName works around a bug in IE 8 with
928 // disabled inputs (#7620)
929 elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false);
930 if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
934 this.mouseDelayMet = !this.options.delay;
935 if (!this.mouseDelayMet) {
936 this._mouseDelayTimer = setTimeout(function() {
937 that.mouseDelayMet = true;
938 }, this.options.delay);
941 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
942 this._mouseStarted = (this._mouseStart(event) !== false);
943 if (!this._mouseStarted) {
944 event.preventDefault();
949 // Click event may never have fired (Gecko & Opera)
950 if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) {
951 $.removeData(event.target, this.widgetName + ".preventClickEvent");
954 // these delegates are required to keep context
955 this._mouseMoveDelegate = function(event) {
956 return that._mouseMove(event);
958 this._mouseUpDelegate = function(event) {
959 return that._mouseUp(event);
963 .bind( "mousemove." + this.widgetName, this._mouseMoveDelegate )
964 .bind( "mouseup." + this.widgetName, this._mouseUpDelegate );
966 event.preventDefault();
972 _mouseMove: function(event) {
973 // Only check for mouseups outside the document if you've moved inside the document
974 // at least once. This prevents the firing of mouseup in the case of IE<9, which will
975 // fire a mousemove event if content is placed under the cursor. See #7778
977 if ( this._mouseMoved ) {
978 // IE mouseup check - mouseup happened when mouse was out of window
979 if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) {
980 return this._mouseUp(event);
982 // Iframe mouseup check - mouseup occurred in another document
983 } else if ( !event.which ) {
984 return this._mouseUp( event );
988 if ( event.which || event.button ) {
989 this._mouseMoved = true;
992 if (this._mouseStarted) {
993 this._mouseDrag(event);
994 return event.preventDefault();
997 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
999 (this._mouseStart(this._mouseDownEvent, event) !== false);
1000 (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
1003 return !this._mouseStarted;
1006 _mouseUp: function(event) {
1008 .unbind( "mousemove." + this.widgetName, this._mouseMoveDelegate )
1009 .unbind( "mouseup." + this.widgetName, this._mouseUpDelegate );
1011 if (this._mouseStarted) {
1012 this._mouseStarted = false;
1014 if (event.target === this._mouseDownEvent.target) {
1015 $.data(event.target, this.widgetName + ".preventClickEvent", true);
1018 this._mouseStop(event);
1021 mouseHandled = false;
1025 _mouseDistanceMet: function(event) {
1027 Math.abs(this._mouseDownEvent.pageX - event.pageX),
1028 Math.abs(this._mouseDownEvent.pageY - event.pageY)
1029 ) >= this.options.distance
1033 _mouseDelayMet: function(/* event */) {
1034 return this.mouseDelayMet;
1037 // These are placeholder methods, to be overriden by extending plugin
1038 _mouseStart: function(/* event */) {},
1039 _mouseDrag: function(/* event */) {},
1040 _mouseStop: function(/* event */) {},
1041 _mouseCapture: function(/* event */) { return true; }
1046 * jQuery UI Position 1.11.4
1047 * http://jqueryui.com
1049 * Copyright jQuery Foundation and other contributors
1050 * Released under the MIT license.
1051 * http://jquery.org/license
1053 * http://api.jqueryui.com/position/
1060 var cachedScrollbarWidth, supportsOffsetFractions,
1064 rhorizontal = /left|center|right/,
1065 rvertical = /top|center|bottom/,
1066 roffset = /[\+\-]\d+(\.[\d]+)?%?/,
1069 _position = $.fn.position;
1071 function getOffsets( offsets, width, height ) {
1073 parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
1074 parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
1078 function parseCss( element, property ) {
1079 return parseInt( $.css( element, property ), 10 ) || 0;
1082 function getDimensions( elem ) {
1084 if ( raw.nodeType === 9 ) {
1086 width: elem.width(),
1087 height: elem.height(),
1088 offset: { top: 0, left: 0 }
1091 if ( $.isWindow( raw ) ) {
1093 width: elem.width(),
1094 height: elem.height(),
1095 offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
1098 if ( raw.preventDefault ) {
1102 offset: { top: raw.pageY, left: raw.pageX }
1106 width: elem.outerWidth(),
1107 height: elem.outerHeight(),
1108 offset: elem.offset()
1113 scrollbarWidth: function() {
1114 if ( cachedScrollbarWidth !== undefined ) {
1115 return cachedScrollbarWidth;
1118 div = $( "<div style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ),
1119 innerDiv = div.children()[0];
1121 $( "body" ).append( div );
1122 w1 = innerDiv.offsetWidth;
1123 div.css( "overflow", "scroll" );
1125 w2 = innerDiv.offsetWidth;
1128 w2 = div[0].clientWidth;
1133 return (cachedScrollbarWidth = w1 - w2);
1135 getScrollInfo: function( within ) {
1136 var overflowX = within.isWindow || within.isDocument ? "" :
1137 within.element.css( "overflow-x" ),
1138 overflowY = within.isWindow || within.isDocument ? "" :
1139 within.element.css( "overflow-y" ),
1140 hasOverflowX = overflowX === "scroll" ||
1141 ( overflowX === "auto" && within.width < within.element[0].scrollWidth ),
1142 hasOverflowY = overflowY === "scroll" ||
1143 ( overflowY === "auto" && within.height < within.element[0].scrollHeight );
1145 width: hasOverflowY ? $.position.scrollbarWidth() : 0,
1146 height: hasOverflowX ? $.position.scrollbarWidth() : 0
1149 getWithinInfo: function( element ) {
1150 var withinElement = $( element || window ),
1151 isWindow = $.isWindow( withinElement[0] ),
1152 isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9;
1154 element: withinElement,
1156 isDocument: isDocument,
1157 offset: withinElement.offset() || { left: 0, top: 0 },
1158 scrollLeft: withinElement.scrollLeft(),
1159 scrollTop: withinElement.scrollTop(),
1161 // support: jQuery 1.6.x
1162 // jQuery 1.6 doesn't support .outerWidth/Height() on documents or windows
1163 width: isWindow || isDocument ? withinElement.width() : withinElement.outerWidth(),
1164 height: isWindow || isDocument ? withinElement.height() : withinElement.outerHeight()
1169 $.fn.position = function( options ) {
1170 if ( !options || !options.of ) {
1171 return _position.apply( this, arguments );
1174 // make a copy, we don't want to modify arguments
1175 options = $.extend( {}, options );
1177 var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
1178 target = $( options.of ),
1179 within = $.position.getWithinInfo( options.within ),
1180 scrollInfo = $.position.getScrollInfo( within ),
1181 collision = ( options.collision || "flip" ).split( " " ),
1184 dimensions = getDimensions( target );
1185 if ( target[0].preventDefault ) {
1186 // force left top to allow flipping
1187 options.at = "left top";
1189 targetWidth = dimensions.width;
1190 targetHeight = dimensions.height;
1191 targetOffset = dimensions.offset;
1192 // clone to reuse original targetOffset later
1193 basePosition = $.extend( {}, targetOffset );
1195 // force my and at to have valid horizontal and vertical positions
1196 // if a value is missing or invalid, it will be converted to center
1197 $.each( [ "my", "at" ], function() {
1198 var pos = ( options[ this ] || "" ).split( " " ),
1202 if ( pos.length === 1) {
1203 pos = rhorizontal.test( pos[ 0 ] ) ?
1204 pos.concat( [ "center" ] ) :
1205 rvertical.test( pos[ 0 ] ) ?
1206 [ "center" ].concat( pos ) :
1207 [ "center", "center" ];
1209 pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
1210 pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
1212 // calculate offsets
1213 horizontalOffset = roffset.exec( pos[ 0 ] );
1214 verticalOffset = roffset.exec( pos[ 1 ] );
1216 horizontalOffset ? horizontalOffset[ 0 ] : 0,
1217 verticalOffset ? verticalOffset[ 0 ] : 0
1220 // reduce to just the positions without the offsets
1222 rposition.exec( pos[ 0 ] )[ 0 ],
1223 rposition.exec( pos[ 1 ] )[ 0 ]
1227 // normalize collision option
1228 if ( collision.length === 1 ) {
1229 collision[ 1 ] = collision[ 0 ];
1232 if ( options.at[ 0 ] === "right" ) {
1233 basePosition.left += targetWidth;
1234 } else if ( options.at[ 0 ] === "center" ) {
1235 basePosition.left += targetWidth / 2;
1238 if ( options.at[ 1 ] === "bottom" ) {
1239 basePosition.top += targetHeight;
1240 } else if ( options.at[ 1 ] === "center" ) {
1241 basePosition.top += targetHeight / 2;
1244 atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
1245 basePosition.left += atOffset[ 0 ];
1246 basePosition.top += atOffset[ 1 ];
1248 return this.each(function() {
1249 var collisionPosition, using,
1251 elemWidth = elem.outerWidth(),
1252 elemHeight = elem.outerHeight(),
1253 marginLeft = parseCss( this, "marginLeft" ),
1254 marginTop = parseCss( this, "marginTop" ),
1255 collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width,
1256 collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height,
1257 position = $.extend( {}, basePosition ),
1258 myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
1260 if ( options.my[ 0 ] === "right" ) {
1261 position.left -= elemWidth;
1262 } else if ( options.my[ 0 ] === "center" ) {
1263 position.left -= elemWidth / 2;
1266 if ( options.my[ 1 ] === "bottom" ) {
1267 position.top -= elemHeight;
1268 } else if ( options.my[ 1 ] === "center" ) {
1269 position.top -= elemHeight / 2;
1272 position.left += myOffset[ 0 ];
1273 position.top += myOffset[ 1 ];
1275 // if the browser doesn't support fractions, then round for consistent results
1276 if ( !supportsOffsetFractions ) {
1277 position.left = round( position.left );
1278 position.top = round( position.top );
1281 collisionPosition = {
1282 marginLeft: marginLeft,
1283 marginTop: marginTop
1286 $.each( [ "left", "top" ], function( i, dir ) {
1287 if ( $.ui.position[ collision[ i ] ] ) {
1288 $.ui.position[ collision[ i ] ][ dir ]( position, {
1289 targetWidth: targetWidth,
1290 targetHeight: targetHeight,
1291 elemWidth: elemWidth,
1292 elemHeight: elemHeight,
1293 collisionPosition: collisionPosition,
1294 collisionWidth: collisionWidth,
1295 collisionHeight: collisionHeight,
1296 offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
1305 if ( options.using ) {
1306 // adds feedback as second argument to using callback, if present
1307 using = function( props ) {
1308 var left = targetOffset.left - position.left,
1309 right = left + targetWidth - elemWidth,
1310 top = targetOffset.top - position.top,
1311 bottom = top + targetHeight - elemHeight,
1315 left: targetOffset.left,
1316 top: targetOffset.top,
1318 height: targetHeight
1322 left: position.left,
1327 horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
1328 vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
1330 if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
1331 feedback.horizontal = "center";
1333 if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
1334 feedback.vertical = "middle";
1336 if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
1337 feedback.important = "horizontal";
1339 feedback.important = "vertical";
1341 options.using.call( this, props, feedback );
1345 elem.offset( $.extend( position, { using: using } ) );
1351 left: function( position, data ) {
1352 var within = data.within,
1353 withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
1354 outerWidth = within.width,
1355 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
1356 overLeft = withinOffset - collisionPosLeft,
1357 overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
1360 // element is wider than within
1361 if ( data.collisionWidth > outerWidth ) {
1362 // element is initially over the left side of within
1363 if ( overLeft > 0 && overRight <= 0 ) {
1364 newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
1365 position.left += overLeft - newOverRight;
1366 // element is initially over right side of within
1367 } else if ( overRight > 0 && overLeft <= 0 ) {
1368 position.left = withinOffset;
1369 // element is initially over both left and right sides of within
1371 if ( overLeft > overRight ) {
1372 position.left = withinOffset + outerWidth - data.collisionWidth;
1374 position.left = withinOffset;
1377 // too far left -> align with left edge
1378 } else if ( overLeft > 0 ) {
1379 position.left += overLeft;
1380 // too far right -> align with right edge
1381 } else if ( overRight > 0 ) {
1382 position.left -= overRight;
1383 // adjust based on position and margin
1385 position.left = max( position.left - collisionPosLeft, position.left );
1388 top: function( position, data ) {
1389 var within = data.within,
1390 withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
1391 outerHeight = data.within.height,
1392 collisionPosTop = position.top - data.collisionPosition.marginTop,
1393 overTop = withinOffset - collisionPosTop,
1394 overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
1397 // element is taller than within
1398 if ( data.collisionHeight > outerHeight ) {
1399 // element is initially over the top of within
1400 if ( overTop > 0 && overBottom <= 0 ) {
1401 newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
1402 position.top += overTop - newOverBottom;
1403 // element is initially over bottom of within
1404 } else if ( overBottom > 0 && overTop <= 0 ) {
1405 position.top = withinOffset;
1406 // element is initially over both top and bottom of within
1408 if ( overTop > overBottom ) {
1409 position.top = withinOffset + outerHeight - data.collisionHeight;
1411 position.top = withinOffset;
1414 // too far up -> align with top
1415 } else if ( overTop > 0 ) {
1416 position.top += overTop;
1417 // too far down -> align with bottom edge
1418 } else if ( overBottom > 0 ) {
1419 position.top -= overBottom;
1420 // adjust based on position and margin
1422 position.top = max( position.top - collisionPosTop, position.top );
1427 left: function( position, data ) {
1428 var within = data.within,
1429 withinOffset = within.offset.left + within.scrollLeft,
1430 outerWidth = within.width,
1431 offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
1432 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
1433 overLeft = collisionPosLeft - offsetLeft,
1434 overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
1435 myOffset = data.my[ 0 ] === "left" ?
1437 data.my[ 0 ] === "right" ?
1440 atOffset = data.at[ 0 ] === "left" ?
1442 data.at[ 0 ] === "right" ?
1445 offset = -2 * data.offset[ 0 ],
1449 if ( overLeft < 0 ) {
1450 newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
1451 if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
1452 position.left += myOffset + atOffset + offset;
1454 } else if ( overRight > 0 ) {
1455 newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;
1456 if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
1457 position.left += myOffset + atOffset + offset;
1461 top: function( position, data ) {
1462 var within = data.within,
1463 withinOffset = within.offset.top + within.scrollTop,
1464 outerHeight = within.height,
1465 offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
1466 collisionPosTop = position.top - data.collisionPosition.marginTop,
1467 overTop = collisionPosTop - offsetTop,
1468 overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
1469 top = data.my[ 1 ] === "top",
1472 data.my[ 1 ] === "bottom" ?
1475 atOffset = data.at[ 1 ] === "top" ?
1477 data.at[ 1 ] === "bottom" ?
1478 -data.targetHeight :
1480 offset = -2 * data.offset[ 1 ],
1483 if ( overTop < 0 ) {
1484 newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
1485 if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) {
1486 position.top += myOffset + atOffset + offset;
1488 } else if ( overBottom > 0 ) {
1489 newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;
1490 if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) {
1491 position.top += myOffset + atOffset + offset;
1498 $.ui.position.flip.left.apply( this, arguments );
1499 $.ui.position.fit.left.apply( this, arguments );
1502 $.ui.position.flip.top.apply( this, arguments );
1503 $.ui.position.fit.top.apply( this, arguments );
1508 // fraction support test
1510 var testElement, testElementParent, testElementStyle, offsetLeft, i,
1511 body = document.getElementsByTagName( "body" )[ 0 ],
1512 div = document.createElement( "div" );
1514 //Create a "fake body" for testing based on method used in jQuery.support
1515 testElement = document.createElement( body ? "div" : "body" );
1516 testElementStyle = {
1517 visibility: "hidden",
1525 $.extend( testElementStyle, {
1526 position: "absolute",
1531 for ( i in testElementStyle ) {
1532 testElement.style[ i ] = testElementStyle[ i ];
1534 testElement.appendChild( div );
1535 testElementParent = body || document.documentElement;
1536 testElementParent.insertBefore( testElement, testElementParent.firstChild );
1538 div.style.cssText = "position: absolute; left: 10.7432222px;";
1540 offsetLeft = $( div ).offset().left;
1541 supportsOffsetFractions = offsetLeft > 10 && offsetLeft < 11;
1543 testElement.innerHTML = "";
1544 testElementParent.removeChild( testElement );
1549 var position = $.ui.position;
1553 * jQuery UI Accordion 1.11.4
1554 * http://jqueryui.com
1556 * Copyright jQuery Foundation and other contributors
1557 * Released under the MIT license.
1558 * http://jquery.org/license
1560 * http://api.jqueryui.com/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 boxSizing = toShow.css( "box-sizing" ),
2057 down = toShow.length &&
2058 ( !toHide.length || ( toShow.index() < toHide.index() ) ),
2059 animate = this.options.animate || {},
2060 options = down && animate.down || animate,
2061 complete = function() {
2062 that._toggleComplete( data );
2065 if ( typeof options === "number" ) {
2068 if ( typeof options === "string" ) {
2071 // fall back from options to animation in case of partial down settings
2072 easing = easing || options.easing || animate.easing;
2073 duration = duration || options.duration || animate.duration;
2075 if ( !toHide.length ) {
2076 return toShow.animate( this.showProps, duration, easing, complete );
2078 if ( !toShow.length ) {
2079 return toHide.animate( this.hideProps, duration, easing, complete );
2082 total = toShow.show().outerHeight();
2083 toHide.animate( this.hideProps, {
2086 step: function( now, fx ) {
2087 fx.now = Math.round( now );
2092 .animate( this.showProps, {
2096 step: function( now, fx ) {
2097 fx.now = Math.round( now );
2098 if ( fx.prop !== "height" ) {
2099 if ( boxSizing === "content-box" ) {
2102 } else if ( that.options.heightStyle !== "content" ) {
2103 fx.now = Math.round( total - toHide.outerHeight() - adjust );
2110 _toggleComplete: function( data ) {
2111 var toHide = data.oldPanel;
2114 .removeClass( "ui-accordion-content-active" )
2116 .removeClass( "ui-corner-top" )
2117 .addClass( "ui-corner-all" );
2119 // Work around for rendering bug in IE (#5421)
2120 if ( toHide.length ) {
2121 toHide.parent()[ 0 ].className = toHide.parent()[ 0 ].className;
2123 this._trigger( "activate", null, data );
2129 * jQuery UI Menu 1.11.4
2130 * http://jqueryui.com
2132 * Copyright jQuery Foundation and other contributors
2133 * Released under the MIT license.
2134 * http://jquery.org/license
2136 * http://api.jqueryui.com/menu/
2140 var menu = $.widget( "ui.menu", {
2142 defaultElement: "<ul>",
2146 submenu: "ui-icon-carat-1-e"
2162 _create: function() {
2163 this.activeMenu = this.element;
2165 // Flag used to prevent firing of the click handler
2166 // as the event bubbles up through nested menus
2167 this.mouseHandled = false;
2170 .addClass( "ui-menu ui-widget ui-widget-content" )
2171 .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length )
2173 role: this.options.role,
2177 if ( this.options.disabled ) {
2179 .addClass( "ui-state-disabled" )
2180 .attr( "aria-disabled", "true" );
2184 // Prevent focus from sticking to links inside menu after clicking
2185 // them (focus should always stay on UL during navigation).
2186 "mousedown .ui-menu-item": function( event ) {
2187 event.preventDefault();
2189 "click .ui-menu-item": function( event ) {
2190 var target = $( event.target );
2191 if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
2192 this.select( event );
2194 // Only set the mouseHandled flag if the event will bubble, see #9469.
2195 if ( !event.isPropagationStopped() ) {
2196 this.mouseHandled = true;
2199 // Open submenu on click
2200 if ( target.has( ".ui-menu" ).length ) {
2201 this.expand( event );
2202 } else if ( !this.element.is( ":focus" ) && $( this.document[ 0 ].activeElement ).closest( ".ui-menu" ).length ) {
2204 // Redirect focus to the menu
2205 this.element.trigger( "focus", [ true ] );
2207 // If the active item is on the top level, let it stay active.
2208 // Otherwise, blur the active item since it is no longer visible.
2209 if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
2210 clearTimeout( this.timer );
2215 "mouseenter .ui-menu-item": function( event ) {
2216 // Ignore mouse events while typeahead is active, see #10458.
2217 // Prevents focusing the wrong item when typeahead causes a scroll while the mouse
2218 // is over an item in the menu
2219 if ( this.previousFilter ) {
2222 var target = $( event.currentTarget );
2223 // Remove ui-state-active class from siblings of the newly focused menu item
2224 // to avoid a jump caused by adjacent elements both having a class with a border
2225 target.siblings( ".ui-state-active" ).removeClass( "ui-state-active" );
2226 this.focus( event, target );
2228 mouseleave: "collapseAll",
2229 "mouseleave .ui-menu": "collapseAll",
2230 focus: function( event, keepActiveItem ) {
2231 // If there's already an active item, keep it active
2232 // If not, activate the first item
2233 var item = this.active || this.element.find( this.options.items ).eq( 0 );
2235 if ( !keepActiveItem ) {
2236 this.focus( event, item );
2239 blur: function( event ) {
2240 this._delay(function() {
2241 if ( !$.contains( this.element[0], this.document[0].activeElement ) ) {
2242 this.collapseAll( event );
2251 // Clicks outside of a menu collapse any open menus
2252 this._on( this.document, {
2253 click: function( event ) {
2254 if ( this._closeOnDocumentClick( event ) ) {
2255 this.collapseAll( event );
2258 // Reset the mouseHandled flag
2259 this.mouseHandled = false;
2264 _destroy: function() {
2265 // Destroy (sub)menus
2267 .removeAttr( "aria-activedescendant" )
2268 .find( ".ui-menu" ).addBack()
2269 .removeClass( "ui-menu ui-widget ui-widget-content ui-menu-icons ui-front" )
2270 .removeAttr( "role" )
2271 .removeAttr( "tabIndex" )
2272 .removeAttr( "aria-labelledby" )
2273 .removeAttr( "aria-expanded" )
2274 .removeAttr( "aria-hidden" )
2275 .removeAttr( "aria-disabled" )
2279 // Destroy menu items
2280 this.element.find( ".ui-menu-item" )
2281 .removeClass( "ui-menu-item" )
2282 .removeAttr( "role" )
2283 .removeAttr( "aria-disabled" )
2285 .removeClass( "ui-state-hover" )
2286 .removeAttr( "tabIndex" )
2287 .removeAttr( "role" )
2288 .removeAttr( "aria-haspopup" )
2289 .children().each( function() {
2290 var elem = $( this );
2291 if ( elem.data( "ui-menu-submenu-carat" ) ) {
2296 // Destroy menu dividers
2297 this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" );
2300 _keydown: function( event ) {
2301 var match, prev, character, skip,
2302 preventDefault = true;
2304 switch ( event.keyCode ) {
2305 case $.ui.keyCode.PAGE_UP:
2306 this.previousPage( event );
2308 case $.ui.keyCode.PAGE_DOWN:
2309 this.nextPage( event );
2311 case $.ui.keyCode.HOME:
2312 this._move( "first", "first", event );
2314 case $.ui.keyCode.END:
2315 this._move( "last", "last", event );
2317 case $.ui.keyCode.UP:
2318 this.previous( event );
2320 case $.ui.keyCode.DOWN:
2323 case $.ui.keyCode.LEFT:
2324 this.collapse( event );
2326 case $.ui.keyCode.RIGHT:
2327 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
2328 this.expand( event );
2331 case $.ui.keyCode.ENTER:
2332 case $.ui.keyCode.SPACE:
2333 this._activate( event );
2335 case $.ui.keyCode.ESCAPE:
2336 this.collapse( event );
2339 preventDefault = false;
2340 prev = this.previousFilter || "";
2341 character = String.fromCharCode( event.keyCode );
2344 clearTimeout( this.filterTimer );
2346 if ( character === prev ) {
2349 character = prev + character;
2352 match = this._filterMenuItems( character );
2353 match = skip && match.index( this.active.next() ) !== -1 ?
2354 this.active.nextAll( ".ui-menu-item" ) :
2357 // If no matches on the current filter, reset to the last character pressed
2358 // to move down the menu to the first item that starts with that character
2359 if ( !match.length ) {
2360 character = String.fromCharCode( event.keyCode );
2361 match = this._filterMenuItems( character );
2364 if ( match.length ) {
2365 this.focus( event, match );
2366 this.previousFilter = character;
2367 this.filterTimer = this._delay(function() {
2368 delete this.previousFilter;
2371 delete this.previousFilter;
2375 if ( preventDefault ) {
2376 event.preventDefault();
2380 _activate: function( event ) {
2381 if ( !this.active.is( ".ui-state-disabled" ) ) {
2382 if ( this.active.is( "[aria-haspopup='true']" ) ) {
2383 this.expand( event );
2385 this.select( event );
2390 refresh: function() {
2393 icon = this.options.icons.submenu,
2394 submenus = this.element.find( this.options.menus );
2396 this.element.toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length );
2398 // Initialize nested menus
2399 submenus.filter( ":not(.ui-menu)" )
2400 .addClass( "ui-menu ui-widget ui-widget-content ui-front" )
2403 role: this.options.role,
2404 "aria-hidden": "true",
2405 "aria-expanded": "false"
2408 var menu = $( this ),
2409 item = menu.parent(),
2410 submenuCarat = $( "<span>" )
2411 .addClass( "ui-menu-icon ui-icon " + icon )
2412 .data( "ui-menu-submenu-carat", true );
2415 .attr( "aria-haspopup", "true" )
2416 .prepend( submenuCarat );
2417 menu.attr( "aria-labelledby", item.attr( "id" ) );
2420 menus = submenus.add( this.element );
2421 items = menus.find( this.options.items );
2423 // Initialize menu-items containing spaces and/or dashes only as dividers
2424 items.not( ".ui-menu-item" ).each(function() {
2425 var item = $( this );
2426 if ( that._isDivider( item ) ) {
2427 item.addClass( "ui-widget-content ui-menu-divider" );
2431 // Don't refresh list items that are already adapted
2432 items.not( ".ui-menu-item, .ui-menu-divider" )
2433 .addClass( "ui-menu-item" )
2437 role: this._itemRole()
2440 // Add aria-disabled attribute to any disabled menu item
2441 items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
2443 // If the active item has been removed, blur the menu
2444 if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
2449 _itemRole: function() {
2453 }[ this.options.role ];
2456 _setOption: function( key, value ) {
2457 if ( key === "icons" ) {
2458 this.element.find( ".ui-menu-icon" )
2459 .removeClass( this.options.icons.submenu )
2460 .addClass( value.submenu );
2462 if ( key === "disabled" ) {
2464 .toggleClass( "ui-state-disabled", !!value )
2465 .attr( "aria-disabled", value );
2467 this._super( key, value );
2470 focus: function( event, item ) {
2471 var nested, focused;
2472 this.blur( event, event && event.type === "focus" );
2474 this._scrollIntoView( item );
2476 this.active = item.first();
2477 focused = this.active.addClass( "ui-state-focus" ).removeClass( "ui-state-active" );
2478 // Only update aria-activedescendant if there's a role
2479 // otherwise we assume focus is managed elsewhere
2480 if ( this.options.role ) {
2481 this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
2484 // Highlight active parent menu item, if any
2487 .closest( ".ui-menu-item" )
2488 .addClass( "ui-state-active" );
2490 if ( event && event.type === "keydown" ) {
2493 this.timer = this._delay(function() {
2498 nested = item.children( ".ui-menu" );
2499 if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) {
2500 this._startOpening(nested);
2502 this.activeMenu = item.parent();
2504 this._trigger( "focus", event, { item: item } );
2507 _scrollIntoView: function( item ) {
2508 var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
2509 if ( this._hasScroll() ) {
2510 borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0;
2511 paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0;
2512 offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
2513 scroll = this.activeMenu.scrollTop();
2514 elementHeight = this.activeMenu.height();
2515 itemHeight = item.outerHeight();
2518 this.activeMenu.scrollTop( scroll + offset );
2519 } else if ( offset + itemHeight > elementHeight ) {
2520 this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
2525 blur: function( event, fromFocus ) {
2527 clearTimeout( this.timer );
2530 if ( !this.active ) {
2534 this.active.removeClass( "ui-state-focus" );
2537 this._trigger( "blur", event, { item: this.active } );
2540 _startOpening: function( submenu ) {
2541 clearTimeout( this.timer );
2543 // Don't open if already open fixes a Firefox bug that caused a .5 pixel
2544 // shift in the submenu position when mousing over the carat icon
2545 if ( submenu.attr( "aria-hidden" ) !== "true" ) {
2549 this.timer = this._delay(function() {
2551 this._open( submenu );
2555 _open: function( submenu ) {
2556 var position = $.extend({
2558 }, this.options.position );
2560 clearTimeout( this.timer );
2561 this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
2563 .attr( "aria-hidden", "true" );
2567 .removeAttr( "aria-hidden" )
2568 .attr( "aria-expanded", "true" )
2569 .position( position );
2572 collapseAll: function( event, all ) {
2573 clearTimeout( this.timer );
2574 this.timer = this._delay(function() {
2575 // If we were passed an event, look for the submenu that contains the event
2576 var currentMenu = all ? this.element :
2577 $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
2579 // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway
2580 if ( !currentMenu.length ) {
2581 currentMenu = this.element;
2584 this._close( currentMenu );
2587 this.activeMenu = currentMenu;
2591 // With no arguments, closes the currently active menu - if nothing is active
2592 // it closes all menus. If passed an argument, it will search for menus BELOW
2593 _close: function( startMenu ) {
2595 startMenu = this.active ? this.active.parent() : this.element;
2601 .attr( "aria-hidden", "true" )
2602 .attr( "aria-expanded", "false" )
2604 .find( ".ui-state-active" ).not( ".ui-state-focus" )
2605 .removeClass( "ui-state-active" );
2608 _closeOnDocumentClick: function( event ) {
2609 return !$( event.target ).closest( ".ui-menu" ).length;
2612 _isDivider: function( item ) {
2614 // Match hyphen, em dash, en dash
2615 return !/[^\-\u2014\u2013\s]/.test( item.text() );
2618 collapse: function( event ) {
2619 var newItem = this.active &&
2620 this.active.parent().closest( ".ui-menu-item", this.element );
2621 if ( newItem && newItem.length ) {
2623 this.focus( event, newItem );
2627 expand: function( event ) {
2628 var newItem = this.active &&
2630 .children( ".ui-menu " )
2631 .find( this.options.items )
2634 if ( newItem && newItem.length ) {
2635 this._open( newItem.parent() );
2637 // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
2638 this._delay(function() {
2639 this.focus( event, newItem );
2644 next: function( event ) {
2645 this._move( "next", "first", event );
2648 previous: function( event ) {
2649 this._move( "prev", "last", event );
2652 isFirstItem: function() {
2653 return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
2656 isLastItem: function() {
2657 return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
2660 _move: function( direction, filter, event ) {
2662 if ( this.active ) {
2663 if ( direction === "first" || direction === "last" ) {
2665 [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
2669 [ direction + "All" ]( ".ui-menu-item" )
2673 if ( !next || !next.length || !this.active ) {
2674 next = this.activeMenu.find( this.options.items )[ filter ]();
2677 this.focus( event, next );
2680 nextPage: function( event ) {
2681 var item, base, height;
2683 if ( !this.active ) {
2687 if ( this.isLastItem() ) {
2690 if ( this._hasScroll() ) {
2691 base = this.active.offset().top;
2692 height = this.element.height();
2693 this.active.nextAll( ".ui-menu-item" ).each(function() {
2695 return item.offset().top - base - height < 0;
2698 this.focus( event, item );
2700 this.focus( event, this.activeMenu.find( this.options.items )
2701 [ !this.active ? "first" : "last" ]() );
2705 previousPage: function( event ) {
2706 var item, base, height;
2707 if ( !this.active ) {
2711 if ( this.isFirstItem() ) {
2714 if ( this._hasScroll() ) {
2715 base = this.active.offset().top;
2716 height = this.element.height();
2717 this.active.prevAll( ".ui-menu-item" ).each(function() {
2719 return item.offset().top - base + height > 0;
2722 this.focus( event, item );
2724 this.focus( event, this.activeMenu.find( this.options.items ).first() );
2728 _hasScroll: function() {
2729 return this.element.outerHeight() < this.element.prop( "scrollHeight" );
2732 select: function( event ) {
2733 // TODO: It should never be possible to not have an active item at this
2734 // point, but the tests don't trigger mouseenter before click.
2735 this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
2736 var ui = { item: this.active };
2737 if ( !this.active.has( ".ui-menu" ).length ) {
2738 this.collapseAll( event, true );
2740 this._trigger( "select", event, ui );
2743 _filterMenuItems: function(character) {
2744 var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ),
2745 regex = new RegExp( "^" + escapedCharacter, "i" );
2747 return this.activeMenu
2748 .find( this.options.items )
2750 // Only match on items, not dividers or other content (#10571)
2751 .filter( ".ui-menu-item" )
2752 .filter(function() {
2753 return regex.test( $.trim( $( this ).text() ) );
2760 * jQuery UI Autocomplete 1.11.4
2761 * http://jqueryui.com
2763 * Copyright jQuery Foundation and other contributors
2764 * Released under the MIT license.
2765 * http://jquery.org/license
2767 * http://api.jqueryui.com/autocomplete/
2771 $.widget( "ui.autocomplete", {
2773 defaultElement: "<input>",
2799 _create: function() {
2800 // Some browsers only repeat keydown events, not keypress events,
2801 // so we use the suppressKeyPress flag to determine if we've already
2802 // handled the keydown event. #7269
2803 // Unfortunately the code for & in keypress is the same as the up arrow,
2804 // so we use the suppressKeyPressRepeat flag to avoid handling keypress
2805 // events when we know the keydown event was used to modify the
2806 // search term. #7799
2807 var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
2808 nodeName = this.element[ 0 ].nodeName.toLowerCase(),
2809 isTextarea = nodeName === "textarea",
2810 isInput = nodeName === "input";
2813 // Textareas are always multi-line
2815 // Inputs are always single-line, even if inside a contentEditable element
2816 // IE also treats inputs as contentEditable
2818 // All other element types are determined by whether or not they're contentEditable
2819 this.element.prop( "isContentEditable" );
2821 this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
2822 this.isNewMenu = true;
2825 .addClass( "ui-autocomplete-input" )
2826 .attr( "autocomplete", "off" );
2828 this._on( this.element, {
2829 keydown: function( event ) {
2830 if ( this.element.prop( "readOnly" ) ) {
2831 suppressKeyPress = true;
2832 suppressInput = true;
2833 suppressKeyPressRepeat = true;
2837 suppressKeyPress = false;
2838 suppressInput = false;
2839 suppressKeyPressRepeat = false;
2840 var keyCode = $.ui.keyCode;
2841 switch ( event.keyCode ) {
2842 case keyCode.PAGE_UP:
2843 suppressKeyPress = true;
2844 this._move( "previousPage", event );
2846 case keyCode.PAGE_DOWN:
2847 suppressKeyPress = true;
2848 this._move( "nextPage", event );
2851 suppressKeyPress = true;
2852 this._keyEvent( "previous", event );
2855 suppressKeyPress = true;
2856 this._keyEvent( "next", event );
2859 // when menu is open and has focus
2860 if ( this.menu.active ) {
2861 // #6055 - Opera still allows the keypress to occur
2862 // which causes forms to submit
2863 suppressKeyPress = true;
2864 event.preventDefault();
2865 this.menu.select( event );
2869 if ( this.menu.active ) {
2870 this.menu.select( event );
2873 case keyCode.ESCAPE:
2874 if ( this.menu.element.is( ":visible" ) ) {
2875 if ( !this.isMultiLine ) {
2876 this._value( this.term );
2878 this.close( event );
2879 // Different browsers have different default behavior for escape
2880 // Single press can mean undo or clear
2881 // Double press in IE means clear the whole form
2882 event.preventDefault();
2886 suppressKeyPressRepeat = true;
2887 // search timeout should be triggered before the input value is changed
2888 this._searchTimeout( event );
2892 keypress: function( event ) {
2893 if ( suppressKeyPress ) {
2894 suppressKeyPress = false;
2895 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
2896 event.preventDefault();
2900 if ( suppressKeyPressRepeat ) {
2904 // replicate some key handlers to allow them to repeat in Firefox and Opera
2905 var keyCode = $.ui.keyCode;
2906 switch ( event.keyCode ) {
2907 case keyCode.PAGE_UP:
2908 this._move( "previousPage", event );
2910 case keyCode.PAGE_DOWN:
2911 this._move( "nextPage", event );
2914 this._keyEvent( "previous", event );
2917 this._keyEvent( "next", event );
2921 input: function( event ) {
2922 if ( suppressInput ) {
2923 suppressInput = false;
2924 event.preventDefault();
2927 this._searchTimeout( event );
2930 this.selectedItem = null;
2931 this.previous = this._value();
2933 blur: function( event ) {
2934 if ( this.cancelBlur ) {
2935 delete this.cancelBlur;
2939 clearTimeout( this.searching );
2940 this.close( event );
2941 this._change( event );
2946 this.menu = $( "<ul>" )
2947 .addClass( "ui-autocomplete ui-front" )
2948 .appendTo( this._appendTo() )
2950 // disable ARIA support, the live region takes care of that
2954 .menu( "instance" );
2956 this._on( this.menu.element, {
2957 mousedown: function( event ) {
2958 // prevent moving focus out of the text field
2959 event.preventDefault();
2961 // IE doesn't prevent moving focus even with event.preventDefault()
2962 // so we set a flag to know when we should ignore the blur event
2963 this.cancelBlur = true;
2964 this._delay(function() {
2965 delete this.cancelBlur;
2968 // clicking on the scrollbar causes focus to shift to the body
2969 // but we can't detect a mouseup or a click immediately afterward
2970 // so we have to track the next mousedown and close the menu if
2971 // the user clicks somewhere outside of the autocomplete
2972 var menuElement = this.menu.element[ 0 ];
2973 if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
2974 this._delay(function() {
2976 this.document.one( "mousedown", function( event ) {
2977 if ( event.target !== that.element[ 0 ] &&
2978 event.target !== menuElement &&
2979 !$.contains( menuElement, event.target ) ) {
2986 menufocus: function( event, ui ) {
2989 // Prevent accidental activation of menu items in Firefox (#7024 #9118)
2990 if ( this.isNewMenu ) {
2991 this.isNewMenu = false;
2992 if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
2995 this.document.one( "mousemove", function() {
2996 $( event.target ).trigger( event.originalEvent );
3003 item = ui.item.data( "ui-autocomplete-item" );
3004 if ( false !== this._trigger( "focus", event, { item: item } ) ) {
3005 // use value to match what will end up in the input, if it was a key event
3006 if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
3007 this._value( item.value );
3011 // Announce the value in the liveRegion
3012 label = ui.item.attr( "aria-label" ) || item.value;
3013 if ( label && $.trim( label ).length ) {
3014 this.liveRegion.children().hide();
3015 $( "<div>" ).text( label ).appendTo( this.liveRegion );
3018 menuselect: function( event, ui ) {
3019 var item = ui.item.data( "ui-autocomplete-item" ),
3020 previous = this.previous;
3022 // only trigger when focus was lost (click on menu)
3023 if ( this.element[ 0 ] !== this.document[ 0 ].activeElement ) {
3024 this.element.focus();
3025 this.previous = previous;
3026 // #6109 - IE triggers two focus events and the second
3027 // is asynchronous, so we need to reset the previous
3028 // term synchronously and asynchronously :-(
3029 this._delay(function() {
3030 this.previous = previous;
3031 this.selectedItem = item;
3035 if ( false !== this._trigger( "select", event, { item: item } ) ) {
3036 this._value( item.value );
3038 // reset the term after the select event
3039 // this allows custom select handling to work properly
3040 this.term = this._value();
3042 this.close( event );
3043 this.selectedItem = item;
3047 this.liveRegion = $( "<span>", {
3049 "aria-live": "assertive",
3050 "aria-relevant": "additions"
3052 .addClass( "ui-helper-hidden-accessible" )
3053 .appendTo( this.document[ 0 ].body );
3055 // turning off autocomplete prevents the browser from remembering the
3056 // value when navigating through history, so we re-enable autocomplete
3057 // if the page is unloaded before the widget is destroyed. #7790
3058 this._on( this.window, {
3059 beforeunload: function() {
3060 this.element.removeAttr( "autocomplete" );
3065 _destroy: function() {
3066 clearTimeout( this.searching );
3068 .removeClass( "ui-autocomplete-input" )
3069 .removeAttr( "autocomplete" );
3070 this.menu.element.remove();
3071 this.liveRegion.remove();
3074 _setOption: function( key, value ) {
3075 this._super( key, value );
3076 if ( key === "source" ) {
3079 if ( key === "appendTo" ) {
3080 this.menu.element.appendTo( this._appendTo() );
3082 if ( key === "disabled" && value && this.xhr ) {
3087 _appendTo: function() {
3088 var element = this.options.appendTo;
3091 element = element.jquery || element.nodeType ?
3093 this.document.find( element ).eq( 0 );
3096 if ( !element || !element[ 0 ] ) {
3097 element = this.element.closest( ".ui-front" );
3100 if ( !element.length ) {
3101 element = this.document[ 0 ].body;
3107 _initSource: function() {
3110 if ( $.isArray( this.options.source ) ) {
3111 array = this.options.source;
3112 this.source = function( request, response ) {
3113 response( $.ui.autocomplete.filter( array, request.term ) );
3115 } else if ( typeof this.options.source === "string" ) {
3116 url = this.options.source;
3117 this.source = function( request, response ) {
3125 success: function( data ) {
3134 this.source = this.options.source;
3138 _searchTimeout: function( event ) {
3139 clearTimeout( this.searching );
3140 this.searching = this._delay(function() {
3142 // Search if the value has changed, or if the user retypes the same value (see #7434)
3143 var equalValues = this.term === this._value(),
3144 menuVisible = this.menu.element.is( ":visible" ),
3145 modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
3147 if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) {
3148 this.selectedItem = null;
3149 this.search( null, event );
3151 }, this.options.delay );
3154 search: function( value, event ) {
3155 value = value != null ? value : this._value();
3157 // always save the actual value, not the one passed as an argument
3158 this.term = this._value();
3160 if ( value.length < this.options.minLength ) {
3161 return this.close( event );
3164 if ( this._trigger( "search", event ) === false ) {
3168 return this._search( value );
3171 _search: function( value ) {
3173 this.element.addClass( "ui-autocomplete-loading" );
3174 this.cancelSearch = false;
3176 this.source( { term: value }, this._response() );
3179 _response: function() {
3180 var index = ++this.requestIndex;
3182 return $.proxy(function( content ) {
3183 if ( index === this.requestIndex ) {
3184 this.__response( content );
3188 if ( !this.pending ) {
3189 this.element.removeClass( "ui-autocomplete-loading" );
3194 __response: function( content ) {
3196 content = this._normalize( content );
3198 this._trigger( "response", null, { content: content } );
3199 if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
3200 this._suggest( content );
3201 this._trigger( "open" );
3203 // use ._close() instead of .close() so we don't cancel future searches
3208 close: function( event ) {
3209 this.cancelSearch = true;
3210 this._close( event );
3213 _close: function( event ) {
3214 if ( this.menu.element.is( ":visible" ) ) {
3215 this.menu.element.hide();
3217 this.isNewMenu = true;
3218 this._trigger( "close", event );
3222 _change: function( event ) {
3223 if ( this.previous !== this._value() ) {
3224 this._trigger( "change", event, { item: this.selectedItem } );
3228 _normalize: function( items ) {
3229 // assume all items have the right format when the first item is complete
3230 if ( items.length && items[ 0 ].label && items[ 0 ].value ) {
3233 return $.map( items, function( item ) {
3234 if ( typeof item === "string" ) {
3240 return $.extend( {}, item, {
3241 label: item.label || item.value,
3242 value: item.value || item.label
3247 _suggest: function( items ) {
3248 var ul = this.menu.element.empty();
3249 this._renderMenu( ul, items );
3250 this.isNewMenu = true;
3251 this.menu.refresh();
3253 // size and position menu
3256 ul.position( $.extend({
3258 }, this.options.position ) );
3260 if ( this.options.autoFocus ) {
3265 _resizeMenu: function() {
3266 var ul = this.menu.element;
3267 ul.outerWidth( Math.max(
3268 // Firefox wraps long text (possibly a rounding bug)
3269 // so we add 1px to avoid the wrapping (#7513)
3270 ul.width( "" ).outerWidth() + 1,
3271 this.element.outerWidth()
3275 _renderMenu: function( ul, items ) {
3277 $.each( items, function( index, item ) {
3278 that._renderItemData( ul, item );
3282 _renderItemData: function( ul, item ) {
3283 return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
3286 _renderItem: function( ul, item ) {
3287 return $( "<li>" ).text( item.label ).appendTo( ul );
3290 _move: function( direction, event ) {
3291 if ( !this.menu.element.is( ":visible" ) ) {
3292 this.search( null, event );
3295 if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
3296 this.menu.isLastItem() && /^next/.test( direction ) ) {
3298 if ( !this.isMultiLine ) {
3299 this._value( this.term );
3305 this.menu[ direction ]( event );
3308 widget: function() {
3309 return this.menu.element;
3312 _value: function() {
3313 return this.valueMethod.apply( this.element, arguments );
3316 _keyEvent: function( keyEvent, event ) {
3317 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
3318 this._move( keyEvent, event );
3320 // prevents moving cursor to beginning/end of the text field in some browsers
3321 event.preventDefault();
3326 $.extend( $.ui.autocomplete, {
3327 escapeRegex: function( value ) {
3328 return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
3330 filter: function( array, term ) {
3331 var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" );
3332 return $.grep( array, function( value ) {
3333 return matcher.test( value.label || value.value || value );
3338 // live region extension, adding a `messages` option
3339 // NOTE: This is an experimental API. We are still investigating
3340 // a full solution for string manipulation and internationalization.
3341 $.widget( "ui.autocomplete", $.ui.autocomplete, {
3344 noResults: "No search results.",
3345 results: function( amount ) {
3346 return amount + ( amount > 1 ? " results are" : " result is" ) +
3347 " available, use up and down arrow keys to navigate.";
3352 __response: function( content ) {
3354 this._superApply( arguments );
3355 if ( this.options.disabled || this.cancelSearch ) {
3358 if ( content && content.length ) {
3359 message = this.options.messages.results( content.length );
3361 message = this.options.messages.noResults;
3363 this.liveRegion.children().hide();
3364 $( "<div>" ).text( message ).appendTo( this.liveRegion );
3368 var autocomplete = $.ui.autocomplete;
3372 * jQuery UI Button 1.11.4
3373 * http://jqueryui.com
3375 * Copyright jQuery Foundation and other contributors
3376 * Released under the MIT license.
3377 * http://jquery.org/license
3379 * http://api.jqueryui.com/button/
3384 baseClasses = "ui-button ui-widget ui-state-default ui-corner-all",
3385 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",
3386 formResetHandler = function() {
3387 var form = $( this );
3388 setTimeout(function() {
3389 form.find( ":ui-button" ).button( "refresh" );
3392 radioGroup = function( radio ) {
3393 var name = radio.name,
3397 name = name.replace( /'/g, "\\'" );
3399 radios = $( form ).find( "[name='" + name + "'][type=radio]" );
3401 radios = $( "[name='" + name + "'][type=radio]", radio.ownerDocument )
3402 .filter(function() {
3410 $.widget( "ui.button", {
3412 defaultElement: "<button>",
3422 _create: function() {
3423 this.element.closest( "form" )
3424 .unbind( "reset" + this.eventNamespace )
3425 .bind( "reset" + this.eventNamespace, formResetHandler );
3427 if ( typeof this.options.disabled !== "boolean" ) {
3428 this.options.disabled = !!this.element.prop( "disabled" );
3430 this.element.prop( "disabled", this.options.disabled );
3433 this._determineButtonType();
3434 this.hasTitle = !!this.buttonElement.attr( "title" );
3437 options = this.options,
3438 toggleButton = this.type === "checkbox" || this.type === "radio",
3439 activeClass = !toggleButton ? "ui-state-active" : "";
3441 if ( options.label === null ) {
3442 options.label = (this.type === "input" ? this.buttonElement.val() : this.buttonElement.html());
3445 this._hoverable( this.buttonElement );
3448 .addClass( baseClasses )
3449 .attr( "role", "button" )
3450 .bind( "mouseenter" + this.eventNamespace, function() {
3451 if ( options.disabled ) {
3454 if ( this === lastActive ) {
3455 $( this ).addClass( "ui-state-active" );
3458 .bind( "mouseleave" + this.eventNamespace, function() {
3459 if ( options.disabled ) {
3462 $( this ).removeClass( activeClass );
3464 .bind( "click" + this.eventNamespace, function( event ) {
3465 if ( options.disabled ) {
3466 event.preventDefault();
3467 event.stopImmediatePropagation();
3471 // Can't use _focusable() because the element that receives focus
3472 // and the element that gets the ui-state-focus class are different
3475 this.buttonElement.addClass( "ui-state-focus" );
3478 this.buttonElement.removeClass( "ui-state-focus" );
3482 if ( toggleButton ) {
3483 this.element.bind( "change" + this.eventNamespace, function() {
3488 if ( this.type === "checkbox" ) {
3489 this.buttonElement.bind( "click" + this.eventNamespace, function() {
3490 if ( options.disabled ) {
3494 } else if ( this.type === "radio" ) {
3495 this.buttonElement.bind( "click" + this.eventNamespace, function() {
3496 if ( options.disabled ) {
3499 $( this ).addClass( "ui-state-active" );
3500 that.buttonElement.attr( "aria-pressed", "true" );
3502 var radio = that.element[ 0 ];
3506 return $( this ).button( "widget" )[ 0 ];
3508 .removeClass( "ui-state-active" )
3509 .attr( "aria-pressed", "false" );
3513 .bind( "mousedown" + this.eventNamespace, function() {
3514 if ( options.disabled ) {
3517 $( this ).addClass( "ui-state-active" );
3519 that.document.one( "mouseup", function() {
3523 .bind( "mouseup" + this.eventNamespace, function() {
3524 if ( options.disabled ) {
3527 $( this ).removeClass( "ui-state-active" );
3529 .bind( "keydown" + this.eventNamespace, function(event) {
3530 if ( options.disabled ) {
3533 if ( event.keyCode === $.ui.keyCode.SPACE || event.keyCode === $.ui.keyCode.ENTER ) {
3534 $( this ).addClass( "ui-state-active" );
3537 // see #8559, we bind to blur here in case the button element loses
3538 // focus between keydown and keyup, it would be left in an "active" state
3539 .bind( "keyup" + this.eventNamespace + " blur" + this.eventNamespace, function() {
3540 $( this ).removeClass( "ui-state-active" );
3543 if ( this.buttonElement.is("a") ) {
3544 this.buttonElement.keyup(function(event) {
3545 if ( event.keyCode === $.ui.keyCode.SPACE ) {
3546 // TODO pass through original event correctly (just as 2nd argument doesn't work)
3553 this._setOption( "disabled", options.disabled );
3554 this._resetButton();
3557 _determineButtonType: function() {
3558 var ancestor, labelSelector, checked;
3560 if ( this.element.is("[type=checkbox]") ) {
3561 this.type = "checkbox";
3562 } else if ( this.element.is("[type=radio]") ) {
3563 this.type = "radio";
3564 } else if ( this.element.is("input") ) {
3565 this.type = "input";
3567 this.type = "button";
3570 if ( this.type === "checkbox" || this.type === "radio" ) {
3571 // we don't search against the document in case the element
3572 // is disconnected from the DOM
3573 ancestor = this.element.parents().last();
3574 labelSelector = "label[for='" + this.element.attr("id") + "']";
3575 this.buttonElement = ancestor.find( labelSelector );
3576 if ( !this.buttonElement.length ) {
3577 ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings();
3578 this.buttonElement = ancestor.filter( labelSelector );
3579 if ( !this.buttonElement.length ) {
3580 this.buttonElement = ancestor.find( labelSelector );
3583 this.element.addClass( "ui-helper-hidden-accessible" );
3585 checked = this.element.is( ":checked" );
3587 this.buttonElement.addClass( "ui-state-active" );
3589 this.buttonElement.prop( "aria-pressed", checked );
3591 this.buttonElement = this.element;
3595 widget: function() {
3596 return this.buttonElement;
3599 _destroy: function() {
3601 .removeClass( "ui-helper-hidden-accessible" );
3603 .removeClass( baseClasses + " ui-state-active " + typeClasses )
3604 .removeAttr( "role" )
3605 .removeAttr( "aria-pressed" )
3606 .html( this.buttonElement.find(".ui-button-text").html() );
3608 if ( !this.hasTitle ) {
3609 this.buttonElement.removeAttr( "title" );
3613 _setOption: function( key, value ) {
3614 this._super( key, value );
3615 if ( key === "disabled" ) {
3616 this.widget().toggleClass( "ui-state-disabled", !!value );
3617 this.element.prop( "disabled", !!value );
3619 if ( this.type === "checkbox" || this.type === "radio" ) {
3620 this.buttonElement.removeClass( "ui-state-focus" );
3622 this.buttonElement.removeClass( "ui-state-focus ui-state-active" );
3627 this._resetButton();
3630 refresh: function() {
3632 var isDisabled = this.element.is( "input, button" ) ? this.element.is( ":disabled" ) : this.element.hasClass( "ui-button-disabled" );
3634 if ( isDisabled !== this.options.disabled ) {
3635 this._setOption( "disabled", isDisabled );
3637 if ( this.type === "radio" ) {
3638 radioGroup( this.element[0] ).each(function() {
3639 if ( $( this ).is( ":checked" ) ) {
3640 $( this ).button( "widget" )
3641 .addClass( "ui-state-active" )
3642 .attr( "aria-pressed", "true" );
3644 $( this ).button( "widget" )
3645 .removeClass( "ui-state-active" )
3646 .attr( "aria-pressed", "false" );
3649 } else if ( this.type === "checkbox" ) {
3650 if ( this.element.is( ":checked" ) ) {
3652 .addClass( "ui-state-active" )
3653 .attr( "aria-pressed", "true" );
3656 .removeClass( "ui-state-active" )
3657 .attr( "aria-pressed", "false" );
3662 _resetButton: function() {
3663 if ( this.type === "input" ) {
3664 if ( this.options.label ) {
3665 this.element.val( this.options.label );
3669 var buttonElement = this.buttonElement.removeClass( typeClasses ),
3670 buttonText = $( "<span></span>", this.document[0] )
3671 .addClass( "ui-button-text" )
3672 .html( this.options.label )
3673 .appendTo( buttonElement.empty() )
3675 icons = this.options.icons,
3676 multipleIcons = icons.primary && icons.secondary,
3679 if ( icons.primary || icons.secondary ) {
3680 if ( this.options.text ) {
3681 buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) );
3684 if ( icons.primary ) {
3685 buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" );
3688 if ( icons.secondary ) {
3689 buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" );
3692 if ( !this.options.text ) {
3693 buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" );
3695 if ( !this.hasTitle ) {
3696 buttonElement.attr( "title", $.trim( buttonText ) );
3700 buttonClasses.push( "ui-button-text-only" );
3702 buttonElement.addClass( buttonClasses.join( " " ) );
3706 $.widget( "ui.buttonset", {
3709 items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)"
3712 _create: function() {
3713 this.element.addClass( "ui-buttonset" );
3720 _setOption: function( key, value ) {
3721 if ( key === "disabled" ) {
3722 this.buttons.button( "option", key, value );
3725 this._super( key, value );
3728 refresh: function() {
3729 var rtl = this.element.css( "direction" ) === "rtl",
3730 allButtons = this.element.find( this.options.items ),
3731 existingButtons = allButtons.filter( ":ui-button" );
3733 // Initialize new buttons
3734 allButtons.not( ":ui-button" ).button();
3736 // Refresh existing buttons
3737 existingButtons.button( "refresh" );
3739 this.buttons = allButtons
3741 return $( this ).button( "widget" )[ 0 ];
3743 .removeClass( "ui-corner-all ui-corner-left ui-corner-right" )
3745 .addClass( rtl ? "ui-corner-right" : "ui-corner-left" )
3748 .addClass( rtl ? "ui-corner-left" : "ui-corner-right" )
3753 _destroy: function() {
3754 this.element.removeClass( "ui-buttonset" );
3757 return $( this ).button( "widget" )[ 0 ];
3759 .removeClass( "ui-corner-left ui-corner-right" )
3761 .button( "destroy" );
3765 var button = $.ui.button;
3769 * jQuery UI Datepicker 1.11.4
3770 * http://jqueryui.com
3772 * Copyright jQuery Foundation and other contributors
3773 * Released under the MIT license.
3774 * http://jquery.org/license
3776 * http://api.jqueryui.com/datepicker/
3780 $.extend($.ui, { datepicker: { version: "1.11.4" } });
3782 var datepicker_instActive;
3784 function datepicker_getZindex( elem ) {
3785 var position, value;
3786 while ( elem.length && elem[ 0 ] !== document ) {
3787 // Ignore z-index if position is set to a value where z-index is ignored by the browser
3788 // This makes behavior of this function consistent across browsers
3789 // WebKit always returns auto if the element is positioned
3790 position = elem.css( "position" );
3791 if ( position === "absolute" || position === "relative" || position === "fixed" ) {
3792 // IE returns 0 when zIndex is not specified
3793 // other browsers return a string
3794 // we ignore the case of nested elements with an explicit value of 0
3795 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
3796 value = parseInt( elem.css( "zIndex" ), 10 );
3797 if ( !isNaN( value ) && value !== 0 ) {
3801 elem = elem.parent();
3806 /* Date picker manager.
3807 Use the singleton instance of this class, $.datepicker, to interact with the date picker.
3808 Settings for (groups of) date pickers are maintained in an instance object,
3809 allowing multiple different settings on the same page. */
3811 function Datepicker() {
3812 this._curInst = null; // The current instance in use
3813 this._keyEvent = false; // If the last event was a key event
3814 this._disabledInputs = []; // List of date picker inputs that have been disabled
3815 this._datepickerShowing = false; // True if the popup picker is showing , false if not
3816 this._inDialog = false; // True if showing within a "dialog", false if not
3817 this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
3818 this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
3819 this._appendClass = "ui-datepicker-append"; // The name of the append marker class
3820 this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
3821 this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
3822 this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
3823 this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
3824 this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
3825 this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
3826 this.regional = []; // Available regional settings, indexed by language code
3827 this.regional[""] = { // Default regional settings
3828 closeText: "Done", // Display text for close link
3829 prevText: "Prev", // Display text for previous month link
3830 nextText: "Next", // Display text for next month link
3831 currentText: "Today", // Display text for current month link
3832 monthNames: ["January","February","March","April","May","June",
3833 "July","August","September","October","November","December"], // Names of months for drop-down and formatting
3834 monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting
3835 dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting
3836 dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting
3837 dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday
3838 weekHeader: "Wk", // Column header for week of the year
3839 dateFormat: "mm/dd/yy", // See format options on parseDate
3840 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
3841 isRTL: false, // True if right-to-left language, false if left-to-right
3842 showMonthAfterYear: false, // True if the year select precedes month, false for month then year
3843 yearSuffix: "" // Additional text to append to the year in the month headers
3845 this._defaults = { // Global defaults for all the date picker instances
3846 showOn: "focus", // "focus" for popup on focus,
3847 // "button" for trigger button, or "both" for either
3848 showAnim: "fadeIn", // Name of jQuery animation for popup
3849 showOptions: {}, // Options for enhanced animations
3850 defaultDate: null, // Used when field is blank: actual date,
3851 // +/-number for offset from today, null for today
3852 appendText: "", // Display text following the input box, e.g. showing the format
3853 buttonText: "...", // Text for trigger button
3854 buttonImage: "", // URL for trigger button image
3855 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
3856 hideIfNoPrevNext: false, // True to hide next/previous month links
3857 // if not applicable, false to just disable them
3858 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
3859 gotoCurrent: false, // True if today link goes back to current selection instead
3860 changeMonth: false, // True if month can be selected directly, false if only prev/next
3861 changeYear: false, // True if year can be selected directly, false if only prev/next
3862 yearRange: "c-10:c+10", // Range of years to display in drop-down,
3863 // either relative to today's year (-nn:+nn), relative to currently displayed year
3864 // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
3865 showOtherMonths: false, // True to show dates in other months, false to leave blank
3866 selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
3867 showWeek: false, // True to show week of the year, false to not show it
3868 calculateWeek: this.iso8601Week, // How to calculate the week of the year,
3869 // takes a Date and returns the number of the week for it
3870 shortYearCutoff: "+10", // Short year values < this are in the current century,
3871 // > this are in the previous century,
3872 // string value starting with "+" for current year + value
3873 minDate: null, // The earliest selectable date, or null for no limit
3874 maxDate: null, // The latest selectable date, or null for no limit
3875 duration: "fast", // Duration of display/closure
3876 beforeShowDay: null, // Function that takes a date and returns an array with
3877 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
3878 // [2] = cell title (optional), e.g. $.datepicker.noWeekends
3879 beforeShow: null, // Function that takes an input field and
3880 // returns a set of custom settings for the date picker
3881 onSelect: null, // Define a callback function when a date is selected
3882 onChangeMonthYear: null, // Define a callback function when the month or year is changed
3883 onClose: null, // Define a callback function when the datepicker is closed
3884 numberOfMonths: 1, // Number of months to show at a time
3885 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
3886 stepMonths: 1, // Number of months to step back/forward
3887 stepBigMonths: 12, // Number of months to step back/forward for the big links
3888 altField: "", // Selector for an alternate field to store selected dates into
3889 altFormat: "", // The date format to use for the alternate field
3890 constrainInput: true, // The input is constrained by the current date format
3891 showButtonPanel: false, // True to show button panel, false to not show it
3892 autoSize: false, // True to size the input for the date format, false to leave as is
3893 disabled: false // The initial disabled state
3895 $.extend(this._defaults, this.regional[""]);
3896 this.regional.en = $.extend( true, {}, this.regional[ "" ]);
3897 this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en );
3898 this.dpDiv = datepicker_bindHover($("<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"));
3901 $.extend(Datepicker.prototype, {
3902 /* Class name added to elements to indicate already configured with a date picker. */
3903 markerClassName: "hasDatepicker",
3905 //Keep track of the maximum number of rows displayed (see #7043)
3908 // TODO rename to "widget" when switching to widget factory
3909 _widgetDatepicker: function() {
3913 /* Override the default settings for all instances of the date picker.
3914 * @param settings object - the new settings to use as defaults (anonymous object)
3915 * @return the manager object
3917 setDefaults: function(settings) {
3918 datepicker_extendRemove(this._defaults, settings || {});
3922 /* Attach the date picker to a jQuery selection.
3923 * @param target element - the target input field or division or span
3924 * @param settings object - the new settings to use for this date picker instance (anonymous)
3926 _attachDatepicker: function(target, settings) {
3927 var nodeName, inline, inst;
3928 nodeName = target.nodeName.toLowerCase();
3929 inline = (nodeName === "div" || nodeName === "span");
3932 target.id = "dp" + this.uuid;
3934 inst = this._newInst($(target), inline);
3935 inst.settings = $.extend({}, settings || {});
3936 if (nodeName === "input") {
3937 this._connectDatepicker(target, inst);
3938 } else if (inline) {
3939 this._inlineDatepicker(target, inst);
3943 /* Create a new instance object. */
3944 _newInst: function(target, inline) {
3945 var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars
3946 return {id: id, input: target, // associated target
3947 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
3948 drawMonth: 0, drawYear: 0, // month being drawn
3949 inline: inline, // is datepicker inline or not
3950 dpDiv: (!inline ? this.dpDiv : // presentation div
3951 datepicker_bindHover($("<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))};
3954 /* Attach the date picker to an input field. */
3955 _connectDatepicker: function(target, inst) {
3956 var input = $(target);
3957 inst.append = $([]);
3958 inst.trigger = $([]);
3959 if (input.hasClass(this.markerClassName)) {
3962 this._attachments(input, inst);
3963 input.addClass(this.markerClassName).keydown(this._doKeyDown).
3964 keypress(this._doKeyPress).keyup(this._doKeyUp);
3965 this._autoSize(inst);
3966 $.data(target, "datepicker", inst);
3967 //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
3968 if( inst.settings.disabled ) {
3969 this._disableDatepicker( target );
3973 /* Make attachments based on settings. */
3974 _attachments: function(input, inst) {
3975 var showOn, buttonText, buttonImage,
3976 appendText = this._get(inst, "appendText"),
3977 isRTL = this._get(inst, "isRTL");
3980 inst.append.remove();
3983 inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>");
3984 input[isRTL ? "before" : "after"](inst.append);
3987 input.unbind("focus", this._showDatepicker);
3990 inst.trigger.remove();
3993 showOn = this._get(inst, "showOn");
3994 if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field
3995 input.focus(this._showDatepicker);
3997 if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked
3998 buttonText = this._get(inst, "buttonText");
3999 buttonImage = this._get(inst, "buttonImage");
4000 inst.trigger = $(this._get(inst, "buttonImageOnly") ?
4001 $("<img/>").addClass(this._triggerClass).
4002 attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
4003 $("<button type='button'></button>").addClass(this._triggerClass).
4004 html(!buttonImage ? buttonText : $("<img/>").attr(
4005 { src:buttonImage, alt:buttonText, title:buttonText })));
4006 input[isRTL ? "before" : "after"](inst.trigger);
4007 inst.trigger.click(function() {
4008 if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) {
4009 $.datepicker._hideDatepicker();
4010 } else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) {
4011 $.datepicker._hideDatepicker();
4012 $.datepicker._showDatepicker(input[0]);
4014 $.datepicker._showDatepicker(input[0]);
4021 /* Apply the maximum length for the date format. */
4022 _autoSize: function(inst) {
4023 if (this._get(inst, "autoSize") && !inst.inline) {
4024 var findMax, max, maxI, i,
4025 date = new Date(2009, 12 - 1, 20), // Ensure double digits
4026 dateFormat = this._get(inst, "dateFormat");
4028 if (dateFormat.match(/[DM]/)) {
4029 findMax = function(names) {
4032 for (i = 0; i < names.length; i++) {
4033 if (names[i].length > max) {
4034 max = names[i].length;
4040 date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
4041 "monthNames" : "monthNamesShort"))));
4042 date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
4043 "dayNames" : "dayNamesShort"))) + 20 - date.getDay());
4045 inst.input.attr("size", this._formatDate(inst, date).length);
4049 /* Attach an inline date picker to a div. */
4050 _inlineDatepicker: function(target, inst) {
4051 var divSpan = $(target);
4052 if (divSpan.hasClass(this.markerClassName)) {
4055 divSpan.addClass(this.markerClassName).append(inst.dpDiv);
4056 $.data(target, "datepicker", inst);
4057 this._setDate(inst, this._getDefaultDate(inst), true);
4058 this._updateDatepicker(inst);
4059 this._updateAlternate(inst);
4060 //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
4061 if( inst.settings.disabled ) {
4062 this._disableDatepicker( target );
4064 // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
4065 // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
4066 inst.dpDiv.css( "display", "block" );
4069 /* Pop-up the date picker in a "dialog" box.
4070 * @param input element - ignored
4071 * @param date string or Date - the initial date to display
4072 * @param onSelect function - the function to call when a date is selected
4073 * @param settings object - update the dialog date picker instance's settings (anonymous object)
4074 * @param pos int[2] - coordinates for the dialog's position within the screen or
4075 * event - with x/y coordinates or
4076 * leave empty for default (screen centre)
4077 * @return the manager object
4079 _dialogDatepicker: function(input, date, onSelect, settings, pos) {
4080 var id, browserWidth, browserHeight, scrollX, scrollY,
4081 inst = this._dialogInst; // internal instance
4085 id = "dp" + this.uuid;
4086 this._dialogInput = $("<input type='text' id='" + id +
4087 "' style='position: absolute; top: -100px; width: 0px;'/>");
4088 this._dialogInput.keydown(this._doKeyDown);
4089 $("body").append(this._dialogInput);
4090 inst = this._dialogInst = this._newInst(this._dialogInput, false);
4092 $.data(this._dialogInput[0], "datepicker", inst);
4094 datepicker_extendRemove(inst.settings, settings || {});
4095 date = (date && date.constructor === Date ? this._formatDate(inst, date) : date);
4096 this._dialogInput.val(date);
4098 this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
4100 browserWidth = document.documentElement.clientWidth;
4101 browserHeight = document.documentElement.clientHeight;
4102 scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
4103 scrollY = document.documentElement.scrollTop || document.body.scrollTop;
4104 this._pos = // should use actual width/height below
4105 [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
4108 // move input on screen for focus, but hidden behind dialog
4109 this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px");
4110 inst.settings.onSelect = onSelect;
4111 this._inDialog = true;
4112 this.dpDiv.addClass(this._dialogClass);
4113 this._showDatepicker(this._dialogInput[0]);
4115 $.blockUI(this.dpDiv);
4117 $.data(this._dialogInput[0], "datepicker", inst);
4121 /* Detach a datepicker from its control.
4122 * @param target element - the target input field or division or span
4124 _destroyDatepicker: function(target) {
4126 $target = $(target),
4127 inst = $.data(target, "datepicker");
4129 if (!$target.hasClass(this.markerClassName)) {
4133 nodeName = target.nodeName.toLowerCase();
4134 $.removeData(target, "datepicker");
4135 if (nodeName === "input") {
4136 inst.append.remove();
4137 inst.trigger.remove();
4138 $target.removeClass(this.markerClassName).
4139 unbind("focus", this._showDatepicker).
4140 unbind("keydown", this._doKeyDown).
4141 unbind("keypress", this._doKeyPress).
4142 unbind("keyup", this._doKeyUp);
4143 } else if (nodeName === "div" || nodeName === "span") {
4144 $target.removeClass(this.markerClassName).empty();
4147 if ( datepicker_instActive === inst ) {
4148 datepicker_instActive = null;
4152 /* Enable the date picker to a jQuery selection.
4153 * @param target element - the target input field or division or span
4155 _enableDatepicker: function(target) {
4156 var nodeName, inline,
4157 $target = $(target),
4158 inst = $.data(target, "datepicker");
4160 if (!$target.hasClass(this.markerClassName)) {
4164 nodeName = target.nodeName.toLowerCase();
4165 if (nodeName === "input") {
4166 target.disabled = false;
4167 inst.trigger.filter("button").
4168 each(function() { this.disabled = false; }).end().
4169 filter("img").css({opacity: "1.0", cursor: ""});
4170 } else if (nodeName === "div" || nodeName === "span") {
4171 inline = $target.children("." + this._inlineClass);
4172 inline.children().removeClass("ui-state-disabled");
4173 inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
4174 prop("disabled", false);
4176 this._disabledInputs = $.map(this._disabledInputs,
4177 function(value) { return (value === target ? null : value); }); // delete entry
4180 /* Disable the date picker to a jQuery selection.
4181 * @param target element - the target input field or division or span
4183 _disableDatepicker: function(target) {
4184 var nodeName, inline,
4185 $target = $(target),
4186 inst = $.data(target, "datepicker");
4188 if (!$target.hasClass(this.markerClassName)) {
4192 nodeName = target.nodeName.toLowerCase();
4193 if (nodeName === "input") {
4194 target.disabled = true;
4195 inst.trigger.filter("button").
4196 each(function() { this.disabled = true; }).end().
4197 filter("img").css({opacity: "0.5", cursor: "default"});
4198 } else if (nodeName === "div" || nodeName === "span") {
4199 inline = $target.children("." + this._inlineClass);
4200 inline.children().addClass("ui-state-disabled");
4201 inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
4202 prop("disabled", true);
4204 this._disabledInputs = $.map(this._disabledInputs,
4205 function(value) { return (value === target ? null : value); }); // delete entry
4206 this._disabledInputs[this._disabledInputs.length] = target;
4209 /* Is the first field in a jQuery collection disabled as a datepicker?
4210 * @param target element - the target input field or division or span
4211 * @return boolean - true if disabled, false if enabled
4213 _isDisabledDatepicker: function(target) {
4217 for (var i = 0; i < this._disabledInputs.length; i++) {
4218 if (this._disabledInputs[i] === target) {
4225 /* Retrieve the instance data for the target control.
4226 * @param target element - the target input field or division or span
4227 * @return object - the associated instance data
4228 * @throws error if a jQuery problem getting data
4230 _getInst: function(target) {
4232 return $.data(target, "datepicker");
4235 throw "Missing instance data for this datepicker";
4239 /* Update or retrieve the settings for a date picker attached to an input field or division.
4240 * @param target element - the target input field or division or span
4241 * @param name object - the new settings to update or
4242 * string - the name of the setting to change or retrieve,
4243 * when retrieving also "all" for all instance settings or
4244 * "defaults" for all global defaults
4245 * @param value any - the new value for the setting
4246 * (omit if above is an object or to retrieve a value)
4248 _optionDatepicker: function(target, name, value) {
4249 var settings, date, minDate, maxDate,
4250 inst = this._getInst(target);
4252 if (arguments.length === 2 && typeof name === "string") {
4253 return (name === "defaults" ? $.extend({}, $.datepicker._defaults) :
4254 (inst ? (name === "all" ? $.extend({}, inst.settings) :
4255 this._get(inst, name)) : null));
4258 settings = name || {};
4259 if (typeof name === "string") {
4261 settings[name] = value;
4265 if (this._curInst === inst) {
4266 this._hideDatepicker();
4269 date = this._getDateDatepicker(target, true);
4270 minDate = this._getMinMaxDate(inst, "min");
4271 maxDate = this._getMinMaxDate(inst, "max");
4272 datepicker_extendRemove(inst.settings, settings);
4273 // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
4274 if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) {
4275 inst.settings.minDate = this._formatDate(inst, minDate);
4277 if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) {
4278 inst.settings.maxDate = this._formatDate(inst, maxDate);
4280 if ( "disabled" in settings ) {
4281 if ( settings.disabled ) {
4282 this._disableDatepicker(target);
4284 this._enableDatepicker(target);
4287 this._attachments($(target), inst);
4288 this._autoSize(inst);
4289 this._setDate(inst, date);
4290 this._updateAlternate(inst);
4291 this._updateDatepicker(inst);
4295 // change method deprecated
4296 _changeDatepicker: function(target, name, value) {
4297 this._optionDatepicker(target, name, value);
4300 /* Redraw the date picker attached to an input field or division.
4301 * @param target element - the target input field or division or span
4303 _refreshDatepicker: function(target) {
4304 var inst = this._getInst(target);
4306 this._updateDatepicker(inst);
4310 /* Set the dates for a jQuery selection.
4311 * @param target element - the target input field or division or span
4312 * @param date Date - the new date
4314 _setDateDatepicker: function(target, date) {
4315 var inst = this._getInst(target);
4317 this._setDate(inst, date);
4318 this._updateDatepicker(inst);
4319 this._updateAlternate(inst);
4323 /* Get the date(s) for the first entry in a jQuery selection.
4324 * @param target element - the target input field or division or span
4325 * @param noDefault boolean - true if no default date is to be used
4326 * @return Date - the current date
4328 _getDateDatepicker: function(target, noDefault) {
4329 var inst = this._getInst(target);
4330 if (inst && !inst.inline) {
4331 this._setDateFromField(inst, noDefault);
4333 return (inst ? this._getDate(inst) : null);
4336 /* Handle keystrokes. */
4337 _doKeyDown: function(event) {
4338 var onSelect, dateStr, sel,
4339 inst = $.datepicker._getInst(event.target),
4341 isRTL = inst.dpDiv.is(".ui-datepicker-rtl");
4343 inst._keyEvent = true;
4344 if ($.datepicker._datepickerShowing) {
4345 switch (event.keyCode) {
4346 case 9: $.datepicker._hideDatepicker();
4348 break; // hide on tab out
4349 case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." +
4350 $.datepicker._currentClass + ")", inst.dpDiv);
4352 $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
4355 onSelect = $.datepicker._get(inst, "onSelect");
4357 dateStr = $.datepicker._formatDate(inst);
4359 // trigger custom callback
4360 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);
4362 $.datepicker._hideDatepicker();
4365 return false; // don't submit the form
4366 case 27: $.datepicker._hideDatepicker();
4367 break; // hide on escape
4368 case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
4369 -$.datepicker._get(inst, "stepBigMonths") :
4370 -$.datepicker._get(inst, "stepMonths")), "M");
4371 break; // previous month/year on page up/+ ctrl
4372 case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
4373 +$.datepicker._get(inst, "stepBigMonths") :
4374 +$.datepicker._get(inst, "stepMonths")), "M");
4375 break; // next month/year on page down/+ ctrl
4376 case 35: if (event.ctrlKey || event.metaKey) {
4377 $.datepicker._clearDate(event.target);
4379 handled = event.ctrlKey || event.metaKey;
4380 break; // clear on ctrl or command +end
4381 case 36: if (event.ctrlKey || event.metaKey) {
4382 $.datepicker._gotoToday(event.target);
4384 handled = event.ctrlKey || event.metaKey;
4385 break; // current on ctrl or command +home
4386 case 37: if (event.ctrlKey || event.metaKey) {
4387 $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D");
4389 handled = event.ctrlKey || event.metaKey;
4390 // -1 day on ctrl or command +left
4391 if (event.originalEvent.altKey) {
4392 $.datepicker._adjustDate(event.target, (event.ctrlKey ?
4393 -$.datepicker._get(inst, "stepBigMonths") :
4394 -$.datepicker._get(inst, "stepMonths")), "M");
4396 // next month/year on alt +left on Mac
4398 case 38: if (event.ctrlKey || event.metaKey) {
4399 $.datepicker._adjustDate(event.target, -7, "D");
4401 handled = event.ctrlKey || event.metaKey;
4402 break; // -1 week on ctrl or command +up
4403 case 39: if (event.ctrlKey || event.metaKey) {
4404 $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D");
4406 handled = event.ctrlKey || event.metaKey;
4407 // +1 day on ctrl or command +right
4408 if (event.originalEvent.altKey) {
4409 $.datepicker._adjustDate(event.target, (event.ctrlKey ?
4410 +$.datepicker._get(inst, "stepBigMonths") :
4411 +$.datepicker._get(inst, "stepMonths")), "M");
4413 // next month/year on alt +right
4415 case 40: if (event.ctrlKey || event.metaKey) {
4416 $.datepicker._adjustDate(event.target, +7, "D");
4418 handled = event.ctrlKey || event.metaKey;
4419 break; // +1 week on ctrl or command +down
4420 default: handled = false;
4422 } else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home
4423 $.datepicker._showDatepicker(this);
4429 event.preventDefault();
4430 event.stopPropagation();
4434 /* Filter entered characters - based on date format. */
4435 _doKeyPress: function(event) {
4437 inst = $.datepicker._getInst(event.target);
4439 if ($.datepicker._get(inst, "constrainInput")) {
4440 chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat"));
4441 chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode);
4442 return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1);
4446 /* Synchronise manual entry and field/alternate field. */
4447 _doKeyUp: function(event) {
4449 inst = $.datepicker._getInst(event.target);
4451 if (inst.input.val() !== inst.lastVal) {
4453 date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
4454 (inst.input ? inst.input.val() : null),
4455 $.datepicker._getFormatConfig(inst));
4457 if (date) { // only if valid
4458 $.datepicker._setDateFromField(inst);
4459 $.datepicker._updateAlternate(inst);
4460 $.datepicker._updateDatepicker(inst);
4469 /* Pop-up the date picker for a given input field.
4470 * If false returned from beforeShow event handler do not show.
4471 * @param input element - the input field attached to the date picker or
4472 * event - if triggered by focus
4474 _showDatepicker: function(input) {
4475 input = input.target || input;
4476 if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger
4477 input = $("input", input.parentNode)[0];
4480 if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here
4484 var inst, beforeShow, beforeShowSettings, isFixed,
4485 offset, showAnim, duration;
4487 inst = $.datepicker._getInst(input);
4488 if ($.datepicker._curInst && $.datepicker._curInst !== inst) {
4489 $.datepicker._curInst.dpDiv.stop(true, true);
4490 if ( inst && $.datepicker._datepickerShowing ) {
4491 $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );
4495 beforeShow = $.datepicker._get(inst, "beforeShow");
4496 beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
4497 if(beforeShowSettings === false){
4500 datepicker_extendRemove(inst.settings, beforeShowSettings);
4502 inst.lastVal = null;
4503 $.datepicker._lastInput = input;
4504 $.datepicker._setDateFromField(inst);
4506 if ($.datepicker._inDialog) { // hide cursor
4509 if (!$.datepicker._pos) { // position below input
4510 $.datepicker._pos = $.datepicker._findPos(input);
4511 $.datepicker._pos[1] += input.offsetHeight; // add the height
4515 $(input).parents().each(function() {
4516 isFixed |= $(this).css("position") === "fixed";
4520 offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
4521 $.datepicker._pos = null;
4522 //to avoid flashes on Firefox
4524 // determine sizing offscreen
4525 inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"});
4526 $.datepicker._updateDatepicker(inst);
4527 // fix width for dynamic number of date pickers
4528 // and adjust position before showing
4529 offset = $.datepicker._checkOffset(inst, offset, isFixed);
4530 inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
4531 "static" : (isFixed ? "fixed" : "absolute")), display: "none",
4532 left: offset.left + "px", top: offset.top + "px"});
4535 showAnim = $.datepicker._get(inst, "showAnim");
4536 duration = $.datepicker._get(inst, "duration");
4537 inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 );
4538 $.datepicker._datepickerShowing = true;
4540 if ( $.effects && $.effects.effect[ showAnim ] ) {
4541 inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration);
4543 inst.dpDiv[showAnim || "show"](showAnim ? duration : null);
4546 if ( $.datepicker._shouldFocusInput( inst ) ) {
4550 $.datepicker._curInst = inst;
4554 /* Generate the date picker content. */
4555 _updateDatepicker: function(inst) {
4556 this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
4557 datepicker_instActive = inst; // for delegate hover events
4558 inst.dpDiv.empty().append(this._generateHTML(inst));
4559 this._attachHandlers(inst);
4562 numMonths = this._getNumberOfMonths(inst),
4563 cols = numMonths[1],
4565 activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" );
4567 if ( activeCell.length > 0 ) {
4568 datepicker_handleMouseover.apply( activeCell.get( 0 ) );
4571 inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");
4573 inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em");
4575 inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") +
4576 "Class"]("ui-datepicker-multi");
4577 inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") +
4578 "Class"]("ui-datepicker-rtl");
4580 if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
4584 // deffered render of the years select (to avoid flashes on Firefox)
4585 if( inst.yearshtml ){
4586 origyearshtml = inst.yearshtml;
4587 setTimeout(function(){
4588 //assure that inst.yearshtml didn't change.
4589 if( origyearshtml === inst.yearshtml && inst.yearshtml ){
4590 inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml);
4592 origyearshtml = inst.yearshtml = null;
4597 // #6694 - don't focus the input if it's already focused
4598 // this breaks the change event in IE
4599 // Support: IE and jQuery <1.9
4600 _shouldFocusInput: function( inst ) {
4601 return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
4604 /* Check positioning to remain on screen. */
4605 _checkOffset: function(inst, offset, isFixed) {
4606 var dpWidth = inst.dpDiv.outerWidth(),
4607 dpHeight = inst.dpDiv.outerHeight(),
4608 inputWidth = inst.input ? inst.input.outerWidth() : 0,
4609 inputHeight = inst.input ? inst.input.outerHeight() : 0,
4610 viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()),
4611 viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop());
4613 offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0);
4614 offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0;
4615 offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
4617 // now check if datepicker is showing outside window viewport - move to a better place if so.
4618 offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
4619 Math.abs(offset.left + dpWidth - viewWidth) : 0);
4620 offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
4621 Math.abs(dpHeight + inputHeight) : 0);
4626 /* Find an object's position on the screen. */
4627 _findPos: function(obj) {
4629 inst = this._getInst(obj),
4630 isRTL = this._get(inst, "isRTL");
4632 while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) {
4633 obj = obj[isRTL ? "previousSibling" : "nextSibling"];
4636 position = $(obj).offset();
4637 return [position.left, position.top];
4640 /* Hide the date picker from view.
4641 * @param input element - the input field attached to the date picker
4643 _hideDatepicker: function(input) {
4644 var showAnim, duration, postProcess, onClose,
4645 inst = this._curInst;
4647 if (!inst || (input && inst !== $.data(input, "datepicker"))) {
4651 if (this._datepickerShowing) {
4652 showAnim = this._get(inst, "showAnim");
4653 duration = this._get(inst, "duration");
4654 postProcess = function() {
4655 $.datepicker._tidyDialog(inst);
4658 // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
4659 if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
4660 inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess);
4662 inst.dpDiv[(showAnim === "slideDown" ? "slideUp" :
4663 (showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess);
4669 this._datepickerShowing = false;
4671 onClose = this._get(inst, "onClose");
4673 onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]);
4676 this._lastInput = null;
4677 if (this._inDialog) {
4678 this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" });
4681 $("body").append(this.dpDiv);
4684 this._inDialog = false;
4688 /* Tidy up after a dialog display. */
4689 _tidyDialog: function(inst) {
4690 inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar");
4693 /* Close date picker if clicked elsewhere. */
4694 _checkExternalClick: function(event) {
4695 if (!$.datepicker._curInst) {
4699 var $target = $(event.target),
4700 inst = $.datepicker._getInst($target[0]);
4702 if ( ( ( $target[0].id !== $.datepicker._mainDivId &&
4703 $target.parents("#" + $.datepicker._mainDivId).length === 0 &&
4704 !$target.hasClass($.datepicker.markerClassName) &&
4705 !$target.closest("." + $.datepicker._triggerClass).length &&
4706 $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) ||
4707 ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) {
4708 $.datepicker._hideDatepicker();
4712 /* Adjust one of the date sub-fields. */
4713 _adjustDate: function(id, offset, period) {
4715 inst = this._getInst(target[0]);
4717 if (this._isDisabledDatepicker(target[0])) {
4720 this._adjustInstDate(inst, offset +
4721 (period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning
4723 this._updateDatepicker(inst);
4726 /* Action for current link. */
4727 _gotoToday: function(id) {
4730 inst = this._getInst(target[0]);
4732 if (this._get(inst, "gotoCurrent") && inst.currentDay) {
4733 inst.selectedDay = inst.currentDay;
4734 inst.drawMonth = inst.selectedMonth = inst.currentMonth;
4735 inst.drawYear = inst.selectedYear = inst.currentYear;
4738 inst.selectedDay = date.getDate();
4739 inst.drawMonth = inst.selectedMonth = date.getMonth();
4740 inst.drawYear = inst.selectedYear = date.getFullYear();
4742 this._notifyChange(inst);
4743 this._adjustDate(target);
4746 /* Action for selecting a new month/year. */
4747 _selectMonthYear: function(id, select, period) {
4749 inst = this._getInst(target[0]);
4751 inst["selected" + (period === "M" ? "Month" : "Year")] =
4752 inst["draw" + (period === "M" ? "Month" : "Year")] =
4753 parseInt(select.options[select.selectedIndex].value,10);
4755 this._notifyChange(inst);
4756 this._adjustDate(target);
4759 /* Action for selecting a day. */
4760 _selectDay: function(id, month, year, td) {
4764 if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
4768 inst = this._getInst(target[0]);
4769 inst.selectedDay = inst.currentDay = $("a", td).html();
4770 inst.selectedMonth = inst.currentMonth = month;
4771 inst.selectedYear = inst.currentYear = year;
4772 this._selectDate(id, this._formatDate(inst,
4773 inst.currentDay, inst.currentMonth, inst.currentYear));
4776 /* Erase the input field and hide the date picker. */
4777 _clearDate: function(id) {
4779 this._selectDate(target, "");
4782 /* Update the input field with the selected date. */
4783 _selectDate: function(id, dateStr) {
4786 inst = this._getInst(target[0]);
4788 dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
4790 inst.input.val(dateStr);
4792 this._updateAlternate(inst);
4794 onSelect = this._get(inst, "onSelect");
4796 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
4797 } else if (inst.input) {
4798 inst.input.trigger("change"); // fire the change event
4802 this._updateDatepicker(inst);
4804 this._hideDatepicker();
4805 this._lastInput = inst.input[0];
4806 if (typeof(inst.input[0]) !== "object") {
4807 inst.input.focus(); // restore focus
4809 this._lastInput = null;
4813 /* Update any alternate field to synchronise with the main field. */
4814 _updateAlternate: function(inst) {
4815 var altFormat, date, dateStr,
4816 altField = this._get(inst, "altField");
4818 if (altField) { // update alternate field too
4819 altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat");
4820 date = this._getDate(inst);
4821 dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
4822 $(altField).each(function() { $(this).val(dateStr); });
4826 /* Set as beforeShowDay function to prevent selection of weekends.
4827 * @param date Date - the date to customise
4828 * @return [boolean, string] - is this date selectable?, what is its CSS class?
4830 noWeekends: function(date) {
4831 var day = date.getDay();
4832 return [(day > 0 && day < 6), ""];
4835 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
4836 * @param date Date - the date to get the week for
4837 * @return number - the number of the week within the year that contains this date
4839 iso8601Week: function(date) {
4841 checkDate = new Date(date.getTime());
4843 // Find Thursday of this week starting on Monday
4844 checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
4846 time = checkDate.getTime();
4847 checkDate.setMonth(0); // Compare with Jan 1
4848 checkDate.setDate(1);
4849 return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
4852 /* Parse a string value into a date object.
4853 * See formatDate below for the possible formats.
4855 * @param format string - the expected format of the date
4856 * @param value string - the date in the above format
4857 * @param settings Object - attributes include:
4858 * shortYearCutoff number - the cutoff year for determining the century (optional)
4859 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
4860 * dayNames string[7] - names of the days from Sunday (optional)
4861 * monthNamesShort string[12] - abbreviated names of the months (optional)
4862 * monthNames string[12] - names of the months (optional)
4863 * @return Date - the extracted date value or null if value is blank
4865 parseDate: function (format, value, settings) {
4866 if (format == null || value == null) {
4867 throw "Invalid arguments";
4870 value = (typeof value === "object" ? value.toString() : value + "");
4875 var iFormat, dim, extra,
4877 shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff,
4878 shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
4879 new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)),
4880 dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
4881 dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
4882 monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
4883 monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
4890 // Check whether a format character is doubled
4891 lookAhead = function(match) {
4892 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
4898 // Extract a number from the string value
4899 getNumber = function(match) {
4900 var isDoubled = lookAhead(match),
4901 size = (match === "@" ? 14 : (match === "!" ? 20 :
4902 (match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))),
4903 minSize = (match === "y" ? size : 1),
4904 digits = new RegExp("^\\d{" + minSize + "," + size + "}"),
4905 num = value.substring(iValue).match(digits);
4907 throw "Missing number at position " + iValue;
4909 iValue += num[0].length;
4910 return parseInt(num[0], 10);
4912 // Extract a name from the string value and convert to an index
4913 getName = function(match, shortNames, longNames) {
4915 names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {
4917 }).sort(function (a, b) {
4918 return -(a[1].length - b[1].length);
4921 $.each(names, function (i, pair) {
4923 if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) {
4925 iValue += name.length;
4932 throw "Unknown name at position " + iValue;
4935 // Confirm that a literal character matches the string value
4936 checkLiteral = function() {
4937 if (value.charAt(iValue) !== format.charAt(iFormat)) {
4938 throw "Unexpected literal at position " + iValue;
4943 for (iFormat = 0; iFormat < format.length; iFormat++) {
4945 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
4951 switch (format.charAt(iFormat)) {
4953 day = getNumber("d");
4956 getName("D", dayNamesShort, dayNames);
4959 doy = getNumber("o");
4962 month = getNumber("m");
4965 month = getName("M", monthNamesShort, monthNames);
4968 year = getNumber("y");
4971 date = new Date(getNumber("@"));
4972 year = date.getFullYear();
4973 month = date.getMonth() + 1;
4974 day = date.getDate();
4977 date = new Date((getNumber("!") - this._ticksTo1970) / 10000);
4978 year = date.getFullYear();
4979 month = date.getMonth() + 1;
4980 day = date.getDate();
4983 if (lookAhead("'")){
4995 if (iValue < value.length){
4996 extra = value.substr(iValue);
4997 if (!/^\s+/.test(extra)) {
4998 throw "Extra/unparsed characters found in date: " + extra;
5003 year = new Date().getFullYear();
5004 } else if (year < 100) {
5005 year += new Date().getFullYear() - new Date().getFullYear() % 100 +
5006 (year <= shortYearCutoff ? 0 : -100);
5013 dim = this._getDaysInMonth(year, month - 1);
5022 date = this._daylightSavingAdjust(new Date(year, month - 1, day));
5023 if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) {
5024 throw "Invalid date"; // E.g. 31/02/00
5029 /* Standard date formats. */
5030 ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
5031 COOKIE: "D, dd M yy",
5032 ISO_8601: "yy-mm-dd",
5033 RFC_822: "D, d M y",
5034 RFC_850: "DD, dd-M-y",
5035 RFC_1036: "D, d M y",
5036 RFC_1123: "D, d M yy",
5037 RFC_2822: "D, d M yy",
5038 RSS: "D, d M y", // RFC 822
5041 W3C: "yy-mm-dd", // ISO 8601
5043 _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
5044 Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
5046 /* Format a date object into a string value.
5047 * The format can be combinations of the following:
5048 * d - day of month (no leading zero)
5049 * dd - day of month (two digit)
5050 * o - day of year (no leading zeros)
5051 * oo - day of year (three digit)
5052 * D - day name short
5053 * DD - day name long
5054 * m - month of year (no leading zero)
5055 * mm - month of year (two digit)
5056 * M - month name short
5057 * MM - month name long
5058 * y - year (two digit)
5059 * yy - year (four digit)
5060 * @ - Unix timestamp (ms since 01/01/1970)
5061 * ! - Windows ticks (100ns since 01/01/0001)
5062 * "..." - literal text
5065 * @param format string - the desired format of the date
5066 * @param date Date - the date value to format
5067 * @param settings Object - attributes include:
5068 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
5069 * dayNames string[7] - names of the days from Sunday (optional)
5070 * monthNamesShort string[12] - abbreviated names of the months (optional)
5071 * monthNames string[12] - names of the months (optional)
5072 * @return string - the date in the above format
5074 formatDate: function (format, date, settings) {
5080 dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
5081 dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
5082 monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
5083 monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
5084 // Check whether a format character is doubled
5085 lookAhead = function(match) {
5086 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
5092 // Format a number, with leading zero if necessary
5093 formatNumber = function(match, value, len) {
5094 var num = "" + value;
5095 if (lookAhead(match)) {
5096 while (num.length < len) {
5102 // Format a name, short or long as requested
5103 formatName = function(match, value, shortNames, longNames) {
5104 return (lookAhead(match) ? longNames[value] : shortNames[value]);
5110 for (iFormat = 0; iFormat < format.length; iFormat++) {
5112 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
5115 output += format.charAt(iFormat);
5118 switch (format.charAt(iFormat)) {
5120 output += formatNumber("d", date.getDate(), 2);
5123 output += formatName("D", date.getDay(), dayNamesShort, dayNames);
5126 output += formatNumber("o",
5127 Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);
5130 output += formatNumber("m", date.getMonth() + 1, 2);
5133 output += formatName("M", date.getMonth(), monthNamesShort, monthNames);
5136 output += (lookAhead("y") ? date.getFullYear() :
5137 (date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100);
5140 output += date.getTime();
5143 output += date.getTime() * 10000 + this._ticksTo1970;
5146 if (lookAhead("'")) {
5153 output += format.charAt(iFormat);
5161 /* Extract all possible characters from the date format. */
5162 _possibleChars: function (format) {
5166 // Check whether a format character is doubled
5167 lookAhead = function(match) {
5168 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
5175 for (iFormat = 0; iFormat < format.length; iFormat++) {
5177 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
5180 chars += format.charAt(iFormat);
5183 switch (format.charAt(iFormat)) {
5184 case "d": case "m": case "y": case "@":
5185 chars += "0123456789";
5188 return null; // Accept anything
5190 if (lookAhead("'")) {
5197 chars += format.charAt(iFormat);
5204 /* Get a setting value, defaulting if necessary. */
5205 _get: function(inst, name) {
5206 return inst.settings[name] !== undefined ?
5207 inst.settings[name] : this._defaults[name];
5210 /* Parse existing date and initialise date picker. */
5211 _setDateFromField: function(inst, noDefault) {
5212 if (inst.input.val() === inst.lastVal) {
5216 var dateFormat = this._get(inst, "dateFormat"),
5217 dates = inst.lastVal = inst.input ? inst.input.val() : null,
5218 defaultDate = this._getDefaultDate(inst),
5220 settings = this._getFormatConfig(inst);
5223 date = this.parseDate(dateFormat, dates, settings) || defaultDate;
5225 dates = (noDefault ? "" : dates);
5227 inst.selectedDay = date.getDate();
5228 inst.drawMonth = inst.selectedMonth = date.getMonth();
5229 inst.drawYear = inst.selectedYear = date.getFullYear();
5230 inst.currentDay = (dates ? date.getDate() : 0);
5231 inst.currentMonth = (dates ? date.getMonth() : 0);
5232 inst.currentYear = (dates ? date.getFullYear() : 0);
5233 this._adjustInstDate(inst);
5236 /* Retrieve the default date shown on opening. */
5237 _getDefaultDate: function(inst) {
5238 return this._restrictMinMax(inst,
5239 this._determineDate(inst, this._get(inst, "defaultDate"), new Date()));
5242 /* A date may be specified as an exact value or a relative one. */
5243 _determineDate: function(inst, date, defaultDate) {
5244 var offsetNumeric = function(offset) {
5245 var date = new Date();
5246 date.setDate(date.getDate() + offset);
5249 offsetString = function(offset) {
5251 return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
5252 offset, $.datepicker._getFormatConfig(inst));
5258 var date = (offset.toLowerCase().match(/^c/) ?
5259 $.datepicker._getDate(inst) : null) || new Date(),
5260 year = date.getFullYear(),
5261 month = date.getMonth(),
5262 day = date.getDate(),
5263 pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
5264 matches = pattern.exec(offset);
5267 switch (matches[2] || "d") {
5268 case "d" : case "D" :
5269 day += parseInt(matches[1],10); break;
5270 case "w" : case "W" :
5271 day += parseInt(matches[1],10) * 7; break;
5272 case "m" : case "M" :
5273 month += parseInt(matches[1],10);
5274 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
5276 case "y": case "Y" :
5277 year += parseInt(matches[1],10);
5278 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
5281 matches = pattern.exec(offset);
5283 return new Date(year, month, day);
5285 newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) :
5286 (typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));
5288 newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate);
5290 newDate.setHours(0);
5291 newDate.setMinutes(0);
5292 newDate.setSeconds(0);
5293 newDate.setMilliseconds(0);
5295 return this._daylightSavingAdjust(newDate);
5298 /* Handle switch to/from daylight saving.
5299 * Hours may be non-zero on daylight saving cut-over:
5300 * > 12 when midnight changeover, but then cannot generate
5301 * midnight datetime, so jump to 1AM, otherwise reset.
5302 * @param date (Date) the date to check
5303 * @return (Date) the corrected date
5305 _daylightSavingAdjust: function(date) {
5309 date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
5313 /* Set the date(s) directly. */
5314 _setDate: function(inst, date, noChange) {
5316 origMonth = inst.selectedMonth,
5317 origYear = inst.selectedYear,
5318 newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
5320 inst.selectedDay = inst.currentDay = newDate.getDate();
5321 inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
5322 inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
5323 if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) {
5324 this._notifyChange(inst);
5326 this._adjustInstDate(inst);
5328 inst.input.val(clear ? "" : this._formatDate(inst));
5332 /* Retrieve the date(s) directly. */
5333 _getDate: function(inst) {
5334 var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null :
5335 this._daylightSavingAdjust(new Date(
5336 inst.currentYear, inst.currentMonth, inst.currentDay)));
5340 /* Attach the onxxx handlers. These are declared statically so
5341 * they work with static code transformers like Caja.
5343 _attachHandlers: function(inst) {
5344 var stepMonths = this._get(inst, "stepMonths"),
5345 id = "#" + inst.id.replace( /\\\\/g, "\\" );
5346 inst.dpDiv.find("[data-handler]").map(function () {
5349 $.datepicker._adjustDate(id, -stepMonths, "M");
5352 $.datepicker._adjustDate(id, +stepMonths, "M");
5355 $.datepicker._hideDatepicker();
5357 today: function () {
5358 $.datepicker._gotoToday(id);
5360 selectDay: function () {
5361 $.datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this);
5364 selectMonth: function () {
5365 $.datepicker._selectMonthYear(id, this, "M");
5368 selectYear: function () {
5369 $.datepicker._selectMonthYear(id, this, "Y");
5373 $(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]);
5377 /* Generate the HTML for the current state of the date picker. */
5378 _generateHTML: function(inst) {
5379 var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
5380 controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
5381 monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
5382 selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
5383 cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
5384 printDate, dRow, tbody, daySettings, otherMonth, unselectable,
5385 tempDate = new Date(),
5386 today = this._daylightSavingAdjust(
5387 new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time
5388 isRTL = this._get(inst, "isRTL"),
5389 showButtonPanel = this._get(inst, "showButtonPanel"),
5390 hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"),
5391 navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"),
5392 numMonths = this._getNumberOfMonths(inst),
5393 showCurrentAtPos = this._get(inst, "showCurrentAtPos"),
5394 stepMonths = this._get(inst, "stepMonths"),
5395 isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1),
5396 currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
5397 new Date(inst.currentYear, inst.currentMonth, inst.currentDay))),
5398 minDate = this._getMinMaxDate(inst, "min"),
5399 maxDate = this._getMinMaxDate(inst, "max"),
5400 drawMonth = inst.drawMonth - showCurrentAtPos,
5401 drawYear = inst.drawYear;
5403 if (drawMonth < 0) {
5408 maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
5409 maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
5410 maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
5411 while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
5413 if (drawMonth < 0) {
5419 inst.drawMonth = drawMonth;
5420 inst.drawYear = drawYear;
5422 prevText = this._get(inst, "prevText");
5423 prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
5424 this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
5425 this._getFormatConfig(inst)));
5427 prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
5428 "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
5429 " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" :
5430 (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>"));
5432 nextText = this._get(inst, "nextText");
5433 nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
5434 this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
5435 this._getFormatConfig(inst)));
5437 next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
5438 "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
5439 " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" :
5440 (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>"));
5442 currentText = this._get(inst, "currentText");
5443 gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today);
5444 currentText = (!navigationAsDateFormat ? currentText :
5445 this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
5447 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'>" +
5448 this._get(inst, "closeText") + "</button>" : "");
5450 buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") +
5451 (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'" +
5452 ">" + currentText + "</button>" : "") + (isRTL ? "" : controls) + "</div>" : "";
5454 firstDay = parseInt(this._get(inst, "firstDay"),10);
5455 firstDay = (isNaN(firstDay) ? 0 : firstDay);
5457 showWeek = this._get(inst, "showWeek");
5458 dayNames = this._get(inst, "dayNames");
5459 dayNamesMin = this._get(inst, "dayNamesMin");
5460 monthNames = this._get(inst, "monthNames");
5461 monthNamesShort = this._get(inst, "monthNamesShort");
5462 beforeShowDay = this._get(inst, "beforeShowDay");
5463 showOtherMonths = this._get(inst, "showOtherMonths");
5464 selectOtherMonths = this._get(inst, "selectOtherMonths");
5465 defaultDate = this._getDefaultDate(inst);
5468 for (row = 0; row < numMonths[0]; row++) {
5471 for (col = 0; col < numMonths[1]; col++) {
5472 selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
5473 cornerClass = " ui-corner-all";
5476 calender += "<div class='ui-datepicker-group";
5477 if (numMonths[1] > 1) {
5479 case 0: calender += " ui-datepicker-group-first";
5480 cornerClass = " ui-corner-" + (isRTL ? "right" : "left"); break;
5481 case numMonths[1]-1: calender += " ui-datepicker-group-last";
5482 cornerClass = " ui-corner-" + (isRTL ? "left" : "right"); break;
5483 default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
5488 calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
5489 (/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") +
5490 (/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") +
5491 this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
5492 row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
5493 "</div><table class='ui-datepicker-calendar'><thead>" +
5495 thead = (showWeek ? "<th class='ui-datepicker-week-col'>" + this._get(inst, "weekHeader") + "</th>" : "");
5496 for (dow = 0; dow < 7; dow++) { // days of the week
5497 day = (dow + firstDay) % 7;
5498 thead += "<th scope='col'" + ((dow + firstDay + 6) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "") + ">" +
5499 "<span title='" + dayNames[day] + "'>" + dayNamesMin[day] + "</span></th>";
5501 calender += thead + "</tr></thead><tbody>";
5502 daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
5503 if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) {
5504 inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
5506 leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
5507 curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate
5508 numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043)
5509 this.maxRows = numRows;
5510 printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
5511 for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows
5513 tbody = (!showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
5514 this._get(inst, "calculateWeek")(printDate) + "</td>");
5515 for (dow = 0; dow < 7; dow++) { // create date picker days
5516 daySettings = (beforeShowDay ?
5517 beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]);
5518 otherMonth = (printDate.getMonth() !== drawMonth);
5519 unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
5520 (minDate && printDate < minDate) || (maxDate && printDate > maxDate);
5521 tbody += "<td class='" +
5522 ((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends
5523 (otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months
5524 ((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key
5525 (defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ?
5526 // or defaultDate is current printedDate and defaultDate is selectedDate
5527 " " + this._dayOverClass : "") + // highlight selected day
5528 (unselectable ? " " + this._unselectableClass + " ui-state-disabled": "") + // highlight unselectable days
5529 (otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates
5530 (printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day
5531 (printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different)
5532 ((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "'") + "'" : "") + // cell title
5533 (unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions
5534 (otherMonth && !showOtherMonths ? " " : // display for other months
5535 (unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
5536 (printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") +
5537 (printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day
5538 (otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months
5539 "' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date
5540 printDate.setDate(printDate.getDate() + 1);
5541 printDate = this._daylightSavingAdjust(printDate);
5543 calender += tbody + "</tr>";
5546 if (drawMonth > 11) {
5550 calender += "</tbody></table>" + (isMultiMonth ? "</div>" +
5551 ((numMonths[0] > 0 && col === numMonths[1]-1) ? "<div class='ui-datepicker-row-break'></div>" : "") : "");
5556 html += buttonPanel;
5557 inst._keyEvent = false;
5561 /* Generate the month and year header. */
5562 _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
5563 secondary, monthNames, monthNamesShort) {
5565 var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
5566 changeMonth = this._get(inst, "changeMonth"),
5567 changeYear = this._get(inst, "changeYear"),
5568 showMonthAfterYear = this._get(inst, "showMonthAfterYear"),
5569 html = "<div class='ui-datepicker-title'>",
5573 if (secondary || !changeMonth) {
5574 monthHtml += "<span class='ui-datepicker-month'>" + monthNames[drawMonth] + "</span>";
5576 inMinYear = (minDate && minDate.getFullYear() === drawYear);
5577 inMaxYear = (maxDate && maxDate.getFullYear() === drawYear);
5578 monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
5579 for ( month = 0; month < 12; month++) {
5580 if ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) {
5581 monthHtml += "<option value='" + month + "'" +
5582 (month === drawMonth ? " selected='selected'" : "") +
5583 ">" + monthNamesShort[month] + "</option>";
5586 monthHtml += "</select>";
5589 if (!showMonthAfterYear) {
5590 html += monthHtml + (secondary || !(changeMonth && changeYear) ? " " : "");
5594 if ( !inst.yearshtml ) {
5595 inst.yearshtml = "";
5596 if (secondary || !changeYear) {
5597 html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
5599 // determine range of years to display
5600 years = this._get(inst, "yearRange").split(":");
5601 thisYear = new Date().getFullYear();
5602 determineYear = function(value) {
5603 var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) :
5604 (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) :
5605 parseInt(value, 10)));
5606 return (isNaN(year) ? thisYear : year);
5608 year = determineYear(years[0]);
5609 endYear = Math.max(year, determineYear(years[1] || ""));
5610 year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
5611 endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
5612 inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
5613 for (; year <= endYear; year++) {
5614 inst.yearshtml += "<option value='" + year + "'" +
5615 (year === drawYear ? " selected='selected'" : "") +
5616 ">" + year + "</option>";
5618 inst.yearshtml += "</select>";
5620 html += inst.yearshtml;
5621 inst.yearshtml = null;
5625 html += this._get(inst, "yearSuffix");
5626 if (showMonthAfterYear) {
5627 html += (secondary || !(changeMonth && changeYear) ? " " : "") + monthHtml;
5629 html += "</div>"; // Close datepicker_header
5633 /* Adjust one of the date sub-fields. */
5634 _adjustInstDate: function(inst, offset, period) {
5635 var year = inst.drawYear + (period === "Y" ? offset : 0),
5636 month = inst.drawMonth + (period === "M" ? offset : 0),
5637 day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0),
5638 date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day)));
5640 inst.selectedDay = date.getDate();
5641 inst.drawMonth = inst.selectedMonth = date.getMonth();
5642 inst.drawYear = inst.selectedYear = date.getFullYear();
5643 if (period === "M" || period === "Y") {
5644 this._notifyChange(inst);
5648 /* Ensure a date is within any min/max bounds. */
5649 _restrictMinMax: function(inst, date) {
5650 var minDate = this._getMinMaxDate(inst, "min"),
5651 maxDate = this._getMinMaxDate(inst, "max"),
5652 newDate = (minDate && date < minDate ? minDate : date);
5653 return (maxDate && newDate > maxDate ? maxDate : newDate);
5656 /* Notify change of month/year. */
5657 _notifyChange: function(inst) {
5658 var onChange = this._get(inst, "onChangeMonthYear");
5660 onChange.apply((inst.input ? inst.input[0] : null),
5661 [inst.selectedYear, inst.selectedMonth + 1, inst]);
5665 /* Determine the number of months to show. */
5666 _getNumberOfMonths: function(inst) {
5667 var numMonths = this._get(inst, "numberOfMonths");
5668 return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths));
5671 /* Determine the current maximum date - ensure no time components are set. */
5672 _getMinMaxDate: function(inst, minMax) {
5673 return this._determineDate(inst, this._get(inst, minMax + "Date"), null);
5676 /* Find the number of days in a given month. */
5677 _getDaysInMonth: function(year, month) {
5678 return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();
5681 /* Find the day of the week of the first of a month. */
5682 _getFirstDayOfMonth: function(year, month) {
5683 return new Date(year, month, 1).getDay();
5686 /* Determines if we should allow a "next/prev" month display change. */
5687 _canAdjustMonth: function(inst, offset, curYear, curMonth) {
5688 var numMonths = this._getNumberOfMonths(inst),
5689 date = this._daylightSavingAdjust(new Date(curYear,
5690 curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
5693 date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
5695 return this._isInRange(inst, date);
5698 /* Is the given date in the accepted range? */
5699 _isInRange: function(inst, date) {
5700 var yearSplit, currentYear,
5701 minDate = this._getMinMaxDate(inst, "min"),
5702 maxDate = this._getMinMaxDate(inst, "max"),
5705 years = this._get(inst, "yearRange");
5707 yearSplit = years.split(":");
5708 currentYear = new Date().getFullYear();
5709 minYear = parseInt(yearSplit[0], 10);
5710 maxYear = parseInt(yearSplit[1], 10);
5711 if ( yearSplit[0].match(/[+\-].*/) ) {
5712 minYear += currentYear;
5714 if ( yearSplit[1].match(/[+\-].*/) ) {
5715 maxYear += currentYear;
5719 return ((!minDate || date.getTime() >= minDate.getTime()) &&
5720 (!maxDate || date.getTime() <= maxDate.getTime()) &&
5721 (!minYear || date.getFullYear() >= minYear) &&
5722 (!maxYear || date.getFullYear() <= maxYear));
5725 /* Provide the configuration settings for formatting/parsing. */
5726 _getFormatConfig: function(inst) {
5727 var shortYearCutoff = this._get(inst, "shortYearCutoff");
5728 shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff :
5729 new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
5730 return {shortYearCutoff: shortYearCutoff,
5731 dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"),
5732 monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")};
5735 /* Format the given date for display. */
5736 _formatDate: function(inst, day, month, year) {
5738 inst.currentDay = inst.selectedDay;
5739 inst.currentMonth = inst.selectedMonth;
5740 inst.currentYear = inst.selectedYear;
5742 var date = (day ? (typeof day === "object" ? day :
5743 this._daylightSavingAdjust(new Date(year, month, day))) :
5744 this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
5745 return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst));
5750 * Bind hover events for datepicker elements.
5751 * Done via delegate so the binding only occurs once in the lifetime of the parent div.
5752 * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
5754 function datepicker_bindHover(dpDiv) {
5755 var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
5756 return dpDiv.delegate(selector, "mouseout", function() {
5757 $(this).removeClass("ui-state-hover");
5758 if (this.className.indexOf("ui-datepicker-prev") !== -1) {
5759 $(this).removeClass("ui-datepicker-prev-hover");
5761 if (this.className.indexOf("ui-datepicker-next") !== -1) {
5762 $(this).removeClass("ui-datepicker-next-hover");
5765 .delegate( selector, "mouseover", datepicker_handleMouseover );
5768 function datepicker_handleMouseover() {
5769 if (!$.datepicker._isDisabledDatepicker( datepicker_instActive.inline? datepicker_instActive.dpDiv.parent()[0] : datepicker_instActive.input[0])) {
5770 $(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");
5771 $(this).addClass("ui-state-hover");
5772 if (this.className.indexOf("ui-datepicker-prev") !== -1) {
5773 $(this).addClass("ui-datepicker-prev-hover");
5775 if (this.className.indexOf("ui-datepicker-next") !== -1) {
5776 $(this).addClass("ui-datepicker-next-hover");
5781 /* jQuery extend now ignores nulls! */
5782 function datepicker_extendRemove(target, props) {
5783 $.extend(target, props);
5784 for (var name in props) {
5785 if (props[name] == null) {
5786 target[name] = props[name];
5792 /* Invoke the datepicker functionality.
5793 @param options string - a command, optionally followed by additional parameters or
5794 Object - settings for attaching new datepicker functionality
5795 @return jQuery object */
5796 $.fn.datepicker = function(options){
5798 /* Verify an empty collection wasn't passed - Fixes #6976 */
5799 if ( !this.length ) {
5803 /* Initialise the date picker. */
5804 if (!$.datepicker.initialized) {
5805 $(document).mousedown($.datepicker._checkExternalClick);
5806 $.datepicker.initialized = true;
5809 /* Append datepicker main container to body if not exist. */
5810 if ($("#"+$.datepicker._mainDivId).length === 0) {
5811 $("body").append($.datepicker.dpDiv);
5814 var otherArgs = Array.prototype.slice.call(arguments, 1);
5815 if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) {
5816 return $.datepicker["_" + options + "Datepicker"].
5817 apply($.datepicker, [this[0]].concat(otherArgs));
5819 if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") {
5820 return $.datepicker["_" + options + "Datepicker"].
5821 apply($.datepicker, [this[0]].concat(otherArgs));
5823 return this.each(function() {
5824 typeof options === "string" ?
5825 $.datepicker["_" + options + "Datepicker"].
5826 apply($.datepicker, [this].concat(otherArgs)) :
5827 $.datepicker._attachDatepicker(this, options);
5831 $.datepicker = new Datepicker(); // singleton instance
5832 $.datepicker.initialized = false;
5833 $.datepicker.uuid = new Date().getTime();
5834 $.datepicker.version = "1.11.4";
5836 var datepicker = $.datepicker;
5840 * jQuery UI Draggable 1.11.4
5841 * http://jqueryui.com
5843 * Copyright jQuery Foundation and other contributors
5844 * Released under the MIT license.
5845 * http://jquery.org/license
5847 * http://api.jqueryui.com/draggable/
5851 $.widget("ui.draggable", $.ui.mouse, {
5853 widgetEventPrefix: "drag",
5858 connectToSortable: false,
5867 refreshPositions: false,
5869 revertDuration: 500,
5872 scrollSensitivity: 20,
5885 _create: function() {
5887 if ( this.options.helper === "original" ) {
5888 this._setPositionRelative();
5890 if (this.options.addClasses){
5891 this.element.addClass("ui-draggable");
5893 if (this.options.disabled){
5894 this.element.addClass("ui-draggable-disabled");
5896 this._setHandleClassName();
5901 _setOption: function( key, value ) {
5902 this._super( key, value );
5903 if ( key === "handle" ) {
5904 this._removeHandleClassName();
5905 this._setHandleClassName();
5909 _destroy: function() {
5910 if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) {
5911 this.destroyOnClear = true;
5914 this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" );
5915 this._removeHandleClassName();
5916 this._mouseDestroy();
5919 _mouseCapture: function(event) {
5920 var o = this.options;
5922 this._blurActiveElement( event );
5924 // among others, prevent a drag on a resizable-handle
5925 if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) {
5929 //Quit if we're not on a valid handle
5930 this.handle = this._getHandle(event);
5935 this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix );
5941 _blockFrames: function( selector ) {
5942 this.iframeBlocks = this.document.find( selector ).map(function() {
5943 var iframe = $( this );
5946 .css( "position", "absolute" )
5947 .appendTo( iframe.parent() )
5948 .outerWidth( iframe.outerWidth() )
5949 .outerHeight( iframe.outerHeight() )
5950 .offset( iframe.offset() )[ 0 ];
5954 _unblockFrames: function() {
5955 if ( this.iframeBlocks ) {
5956 this.iframeBlocks.remove();
5957 delete this.iframeBlocks;
5961 _blurActiveElement: function( event ) {
5962 var document = this.document[ 0 ];
5964 // Only need to blur if the event occurred on the draggable itself, see #10527
5965 if ( !this.handleElement.is( event.target ) ) {
5970 // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
5973 // Support: IE9, IE10
5974 // If the <body> is blurred, IE will switch windows, see #9520
5975 if ( document.activeElement && document.activeElement.nodeName.toLowerCase() !== "body" ) {
5977 // Blur any element that currently has focus, see #4261
5978 $( document.activeElement ).blur();
5980 } catch ( error ) {}
5983 _mouseStart: function(event) {
5985 var o = this.options;
5987 //Create and append the visible helper
5988 this.helper = this._createHelper(event);
5990 this.helper.addClass("ui-draggable-dragging");
5992 //Cache the helper size
5993 this._cacheHelperProportions();
5995 //If ddmanager is used for droppables, set the global draggable
5996 if ($.ui.ddmanager) {
5997 $.ui.ddmanager.current = this;
6001 * - Position generation -
6002 * This block generates everything position related - it's the core of draggables.
6005 //Cache the margins of the original element
6006 this._cacheMargins();
6008 //Store the helper's css position
6009 this.cssPosition = this.helper.css( "position" );
6010 this.scrollParent = this.helper.scrollParent( true );
6011 this.offsetParent = this.helper.offsetParent();
6012 this.hasFixedAncestor = this.helper.parents().filter(function() {
6013 return $( this ).css( "position" ) === "fixed";
6016 //The element's absolute position on the page minus margins
6017 this.positionAbs = this.element.offset();
6018 this._refreshOffsets( event );
6020 //Generate the original position
6021 this.originalPosition = this.position = this._generatePosition( event, false );
6022 this.originalPageX = event.pageX;
6023 this.originalPageY = event.pageY;
6025 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
6026 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
6028 //Set a containment if given in the options
6029 this._setContainment();
6031 //Trigger event + callbacks
6032 if (this._trigger("start", event) === false) {
6037 //Recache the helper size
6038 this._cacheHelperProportions();
6040 //Prepare the droppable offsets
6041 if ($.ui.ddmanager && !o.dropBehaviour) {
6042 $.ui.ddmanager.prepareOffsets(this, event);
6045 // Reset helper's right/bottom css if they're set and set explicit width/height instead
6046 // as this prevents resizing of elements with right/bottom set (see #7772)
6047 this._normalizeRightBottom();
6049 this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
6051 //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
6052 if ( $.ui.ddmanager ) {
6053 $.ui.ddmanager.dragStart(this, event);
6059 _refreshOffsets: function( event ) {
6061 top: this.positionAbs.top - this.margins.top,
6062 left: this.positionAbs.left - this.margins.left,
6064 parent: this._getParentOffset(),
6065 relative: this._getRelativeOffset()
6068 this.offset.click = {
6069 left: event.pageX - this.offset.left,
6070 top: event.pageY - this.offset.top
6074 _mouseDrag: function(event, noPropagation) {
6075 // reset any necessary cached properties (see #5009)
6076 if ( this.hasFixedAncestor ) {
6077 this.offset.parent = this._getParentOffset();
6080 //Compute the helpers position
6081 this.position = this._generatePosition( event, true );
6082 this.positionAbs = this._convertPositionTo("absolute");
6084 //Call plugins and callbacks and use the resulting position if something is returned
6085 if (!noPropagation) {
6086 var ui = this._uiHash();
6087 if (this._trigger("drag", event, ui) === false) {
6091 this.position = ui.position;
6094 this.helper[ 0 ].style.left = this.position.left + "px";
6095 this.helper[ 0 ].style.top = this.position.top + "px";
6097 if ($.ui.ddmanager) {
6098 $.ui.ddmanager.drag(this, event);
6104 _mouseStop: function(event) {
6106 //If we are using droppables, inform the manager about the drop
6109 if ($.ui.ddmanager && !this.options.dropBehaviour) {
6110 dropped = $.ui.ddmanager.drop(this, event);
6113 //if a drop comes from outside (a sortable)
6115 dropped = this.dropped;
6116 this.dropped = false;
6119 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))) {
6120 $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
6121 if (that._trigger("stop", event) !== false) {
6126 if (this._trigger("stop", event) !== false) {
6134 _mouseUp: function( event ) {
6135 this._unblockFrames();
6137 //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003)
6138 if ( $.ui.ddmanager ) {
6139 $.ui.ddmanager.dragStop(this, event);
6142 // Only need to focus if the event occurred on the draggable itself, see #10527
6143 if ( this.handleElement.is( event.target ) ) {
6144 // The interaction is over; whether or not the click resulted in a drag, focus the element
6145 this.element.focus();
6148 return $.ui.mouse.prototype._mouseUp.call(this, event);
6151 cancel: function() {
6153 if (this.helper.is(".ui-draggable-dragging")) {
6163 _getHandle: function(event) {
6164 return this.options.handle ?
6165 !!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
6169 _setHandleClassName: function() {
6170 this.handleElement = this.options.handle ?
6171 this.element.find( this.options.handle ) : this.element;
6172 this.handleElement.addClass( "ui-draggable-handle" );
6175 _removeHandleClassName: function() {
6176 this.handleElement.removeClass( "ui-draggable-handle" );
6179 _createHelper: function(event) {
6181 var o = this.options,
6182 helperIsFunction = $.isFunction( o.helper ),
6183 helper = helperIsFunction ?
6184 $( o.helper.apply( this.element[ 0 ], [ event ] ) ) :
6185 ( o.helper === "clone" ?
6186 this.element.clone().removeAttr( "id" ) :
6189 if (!helper.parents("body").length) {
6190 helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo));
6193 // http://bugs.jqueryui.com/ticket/9446
6194 // a helper function can return the original element
6195 // which wouldn't have been set to relative in _create
6196 if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) {
6197 this._setPositionRelative();
6200 if (helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) {
6201 helper.css("position", "absolute");
6208 _setPositionRelative: function() {
6209 if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) {
6210 this.element[ 0 ].style.position = "relative";
6214 _adjustOffsetFromHelper: function(obj) {
6215 if (typeof obj === "string") {
6216 obj = obj.split(" ");
6218 if ($.isArray(obj)) {
6219 obj = { left: +obj[0], top: +obj[1] || 0 };
6221 if ("left" in obj) {
6222 this.offset.click.left = obj.left + this.margins.left;
6224 if ("right" in obj) {
6225 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
6228 this.offset.click.top = obj.top + this.margins.top;
6230 if ("bottom" in obj) {
6231 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
6235 _isRootNode: function( element ) {
6236 return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ];
6239 _getParentOffset: function() {
6241 //Get the offsetParent and cache its position
6242 var po = this.offsetParent.offset(),
6243 document = this.document[ 0 ];
6245 // This is a special case where we need to modify a offset calculated on start, since the following happened:
6246 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
6247 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
6248 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
6249 if (this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
6250 po.left += this.scrollParent.scrollLeft();
6251 po.top += this.scrollParent.scrollTop();
6254 if ( this._isRootNode( this.offsetParent[ 0 ] ) ) {
6255 po = { top: 0, left: 0 };
6259 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"), 10) || 0),
6260 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"), 10) || 0)
6265 _getRelativeOffset: function() {
6266 if ( this.cssPosition !== "relative" ) {
6267 return { top: 0, left: 0 };
6270 var p = this.element.position(),
6271 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
6274 top: p.top - ( parseInt(this.helper.css( "top" ), 10) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ),
6275 left: p.left - ( parseInt(this.helper.css( "left" ), 10) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 )
6280 _cacheMargins: function() {
6282 left: (parseInt(this.element.css("marginLeft"), 10) || 0),
6283 top: (parseInt(this.element.css("marginTop"), 10) || 0),
6284 right: (parseInt(this.element.css("marginRight"), 10) || 0),
6285 bottom: (parseInt(this.element.css("marginBottom"), 10) || 0)
6289 _cacheHelperProportions: function() {
6290 this.helperProportions = {
6291 width: this.helper.outerWidth(),
6292 height: this.helper.outerHeight()
6296 _setContainment: function() {
6298 var isUserScrollable, c, ce,
6300 document = this.document[ 0 ];
6302 this.relativeContainer = null;
6304 if ( !o.containment ) {
6305 this.containment = null;
6309 if ( o.containment === "window" ) {
6310 this.containment = [
6311 $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
6312 $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
6313 $( window ).scrollLeft() + $( window ).width() - this.helperProportions.width - this.margins.left,
6314 $( window ).scrollTop() + ( $( window ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
6319 if ( o.containment === "document") {
6320 this.containment = [
6323 $( document ).width() - this.helperProportions.width - this.margins.left,
6324 ( $( document ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
6329 if ( o.containment.constructor === Array ) {
6330 this.containment = o.containment;
6334 if ( o.containment === "parent" ) {
6335 o.containment = this.helper[ 0 ].parentNode;
6338 c = $( o.containment );
6345 isUserScrollable = /(scroll|auto)/.test( c.css( "overflow" ) );
6347 this.containment = [
6348 ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
6349 ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ),
6350 ( isUserScrollable ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
6351 ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) -
6352 ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) -
6353 this.helperProportions.width -
6356 ( isUserScrollable ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
6357 ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) -
6358 ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) -
6359 this.helperProportions.height -
6363 this.relativeContainer = c;
6366 _convertPositionTo: function(d, pos) {
6369 pos = this.position;
6372 var mod = d === "absolute" ? 1 : -1,
6373 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
6377 pos.top + // The absolute mouse position
6378 this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
6379 this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
6380 ( ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod)
6383 pos.left + // The absolute mouse position
6384 this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
6385 this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
6386 ( ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod)
6392 _generatePosition: function( event, constrainPosition ) {
6394 var containment, co, top, left,
6396 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ),
6397 pageX = event.pageX,
6398 pageY = event.pageY;
6401 if ( !scrollIsRootNode || !this.offset.scroll ) {
6402 this.offset.scroll = {
6403 top: this.scrollParent.scrollTop(),
6404 left: this.scrollParent.scrollLeft()
6409 * - Position constraining -
6410 * Constrain the position to a mix of grid, containment.
6413 // If we are not dragging yet, we won't check for options
6414 if ( constrainPosition ) {
6415 if ( this.containment ) {
6416 if ( this.relativeContainer ){
6417 co = this.relativeContainer.offset();
6419 this.containment[ 0 ] + co.left,
6420 this.containment[ 1 ] + co.top,
6421 this.containment[ 2 ] + co.left,
6422 this.containment[ 3 ] + co.top
6425 containment = this.containment;
6428 if (event.pageX - this.offset.click.left < containment[0]) {
6429 pageX = containment[0] + this.offset.click.left;
6431 if (event.pageY - this.offset.click.top < containment[1]) {
6432 pageY = containment[1] + this.offset.click.top;
6434 if (event.pageX - this.offset.click.left > containment[2]) {
6435 pageX = containment[2] + this.offset.click.left;
6437 if (event.pageY - this.offset.click.top > containment[3]) {
6438 pageY = containment[3] + this.offset.click.top;
6443 //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950)
6444 top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY;
6445 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;
6447 left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX;
6448 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;
6451 if ( o.axis === "y" ) {
6452 pageX = this.originalPageX;
6455 if ( o.axis === "x" ) {
6456 pageY = this.originalPageY;
6462 pageY - // The absolute mouse position
6463 this.offset.click.top - // Click offset (relative to the element)
6464 this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
6465 this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
6466 ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) )
6469 pageX - // The absolute mouse position
6470 this.offset.click.left - // Click offset (relative to the element)
6471 this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
6472 this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
6473 ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) )
6479 _clear: function() {
6480 this.helper.removeClass("ui-draggable-dragging");
6481 if (this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) {
6482 this.helper.remove();
6485 this.cancelHelperRemoval = false;
6486 if ( this.destroyOnClear ) {
6491 _normalizeRightBottom: function() {
6492 if ( this.options.axis !== "y" && this.helper.css( "right" ) !== "auto" ) {
6493 this.helper.width( this.helper.width() );
6494 this.helper.css( "right", "auto" );
6496 if ( this.options.axis !== "x" && this.helper.css( "bottom" ) !== "auto" ) {
6497 this.helper.height( this.helper.height() );
6498 this.helper.css( "bottom", "auto" );
6502 // From now on bulk stuff - mainly helpers
6504 _trigger: function( type, event, ui ) {
6505 ui = ui || this._uiHash();
6506 $.ui.plugin.call( this, type, [ event, ui, this ], true );
6508 // Absolute position and offset (see #6884 ) have to be recalculated after plugins
6509 if ( /^(drag|start|stop)/.test( type ) ) {
6510 this.positionAbs = this._convertPositionTo( "absolute" );
6511 ui.offset = this.positionAbs;
6513 return $.Widget.prototype._trigger.call( this, type, event, ui );
6518 _uiHash: function() {
6520 helper: this.helper,
6521 position: this.position,
6522 originalPosition: this.originalPosition,
6523 offset: this.positionAbs
6529 $.ui.plugin.add( "draggable", "connectToSortable", {
6530 start: function( event, ui, draggable ) {
6531 var uiSortable = $.extend( {}, ui, {
6532 item: draggable.element
6535 draggable.sortables = [];
6536 $( draggable.options.connectToSortable ).each(function() {
6537 var sortable = $( this ).sortable( "instance" );
6539 if ( sortable && !sortable.options.disabled ) {
6540 draggable.sortables.push( sortable );
6542 // refreshPositions is called at drag start to refresh the containerCache
6543 // which is used in drag. This ensures it's initialized and synchronized
6544 // with any changes that might have happened on the page since initialization.
6545 sortable.refreshPositions();
6546 sortable._trigger("activate", event, uiSortable);
6550 stop: function( event, ui, draggable ) {
6551 var uiSortable = $.extend( {}, ui, {
6552 item: draggable.element
6555 draggable.cancelHelperRemoval = false;
6557 $.each( draggable.sortables, function() {
6558 var sortable = this;
6560 if ( sortable.isOver ) {
6561 sortable.isOver = 0;
6563 // Allow this sortable to handle removing the helper
6564 draggable.cancelHelperRemoval = true;
6565 sortable.cancelHelperRemoval = false;
6567 // Use _storedCSS To restore properties in the sortable,
6568 // as this also handles revert (#9675) since the draggable
6569 // may have modified them in unexpected ways (#8809)
6570 sortable._storedCSS = {
6571 position: sortable.placeholder.css( "position" ),
6572 top: sortable.placeholder.css( "top" ),
6573 left: sortable.placeholder.css( "left" )
6576 sortable._mouseStop(event);
6578 // Once drag has ended, the sortable should return to using
6579 // its original helper, not the shared helper from draggable
6580 sortable.options.helper = sortable.options._helper;
6582 // Prevent this Sortable from removing the helper.
6583 // However, don't set the draggable to remove the helper
6584 // either as another connected Sortable may yet handle the removal.
6585 sortable.cancelHelperRemoval = true;
6587 sortable._trigger( "deactivate", event, uiSortable );
6591 drag: function( event, ui, draggable ) {
6592 $.each( draggable.sortables, function() {
6593 var innermostIntersecting = false,
6596 // Copy over variables that sortable's _intersectsWith uses
6597 sortable.positionAbs = draggable.positionAbs;
6598 sortable.helperProportions = draggable.helperProportions;
6599 sortable.offset.click = draggable.offset.click;
6601 if ( sortable._intersectsWith( sortable.containerCache ) ) {
6602 innermostIntersecting = true;
6604 $.each( draggable.sortables, function() {
6605 // Copy over variables that sortable's _intersectsWith uses
6606 this.positionAbs = draggable.positionAbs;
6607 this.helperProportions = draggable.helperProportions;
6608 this.offset.click = draggable.offset.click;
6610 if ( this !== sortable &&
6611 this._intersectsWith( this.containerCache ) &&
6612 $.contains( sortable.element[ 0 ], this.element[ 0 ] ) ) {
6613 innermostIntersecting = false;
6616 return innermostIntersecting;
6620 if ( innermostIntersecting ) {
6621 // If it intersects, we use a little isOver variable and set it once,
6622 // so that the move-in stuff gets fired only once.
6623 if ( !sortable.isOver ) {
6624 sortable.isOver = 1;
6626 // Store draggable's parent in case we need to reappend to it later.
6627 draggable._parent = ui.helper.parent();
6629 sortable.currentItem = ui.helper
6630 .appendTo( sortable.element )
6631 .data( "ui-sortable-item", true );
6633 // Store helper option to later restore it
6634 sortable.options._helper = sortable.options.helper;
6636 sortable.options.helper = function() {
6637 return ui.helper[ 0 ];
6640 // Fire the start events of the sortable with our passed browser event,
6641 // and our own helper (so it doesn't create a new one)
6642 event.target = sortable.currentItem[ 0 ];
6643 sortable._mouseCapture( event, true );
6644 sortable._mouseStart( event, true, true );
6646 // Because the browser event is way off the new appended portlet,
6647 // modify necessary variables to reflect the changes
6648 sortable.offset.click.top = draggable.offset.click.top;
6649 sortable.offset.click.left = draggable.offset.click.left;
6650 sortable.offset.parent.left -= draggable.offset.parent.left -
6651 sortable.offset.parent.left;
6652 sortable.offset.parent.top -= draggable.offset.parent.top -
6653 sortable.offset.parent.top;
6655 draggable._trigger( "toSortable", event );
6657 // Inform draggable that the helper is in a valid drop zone,
6658 // used solely in the revert option to handle "valid/invalid".
6659 draggable.dropped = sortable.element;
6661 // Need to refreshPositions of all sortables in the case that
6662 // adding to one sortable changes the location of the other sortables (#9675)
6663 $.each( draggable.sortables, function() {
6664 this.refreshPositions();
6667 // hack so receive/update callbacks work (mostly)
6668 draggable.currentItem = draggable.element;
6669 sortable.fromOutside = draggable;
6672 if ( sortable.currentItem ) {
6673 sortable._mouseDrag( event );
6674 // Copy the sortable's position because the draggable's can potentially reflect
6675 // a relative position, while sortable is always absolute, which the dragged
6676 // element has now become. (#8809)
6677 ui.position = sortable.position;
6680 // If it doesn't intersect with the sortable, and it intersected before,
6681 // we fake the drag stop of the sortable, but make sure it doesn't remove
6682 // the helper by using cancelHelperRemoval.
6683 if ( sortable.isOver ) {
6685 sortable.isOver = 0;
6686 sortable.cancelHelperRemoval = true;
6688 // Calling sortable's mouseStop would trigger a revert,
6689 // so revert must be temporarily false until after mouseStop is called.
6690 sortable.options._revert = sortable.options.revert;
6691 sortable.options.revert = false;
6693 sortable._trigger( "out", event, sortable._uiHash( sortable ) );
6694 sortable._mouseStop( event, true );
6696 // restore sortable behaviors that were modfied
6697 // when the draggable entered the sortable area (#9481)
6698 sortable.options.revert = sortable.options._revert;
6699 sortable.options.helper = sortable.options._helper;
6701 if ( sortable.placeholder ) {
6702 sortable.placeholder.remove();
6705 // Restore and recalculate the draggable's offset considering the sortable
6706 // may have modified them in unexpected ways. (#8809, #10669)
6707 ui.helper.appendTo( draggable._parent );
6708 draggable._refreshOffsets( event );
6709 ui.position = draggable._generatePosition( event, true );
6711 draggable._trigger( "fromSortable", event );
6713 // Inform draggable that the helper is no longer in a valid drop zone
6714 draggable.dropped = false;
6716 // Need to refreshPositions of all sortables just in case removing
6717 // from one sortable changes the location of other sortables (#9675)
6718 $.each( draggable.sortables, function() {
6719 this.refreshPositions();
6727 $.ui.plugin.add("draggable", "cursor", {
6728 start: function( event, ui, instance ) {
6729 var t = $( "body" ),
6730 o = instance.options;
6732 if (t.css("cursor")) {
6733 o._cursor = t.css("cursor");
6735 t.css("cursor", o.cursor);
6737 stop: function( event, ui, instance ) {
6738 var o = instance.options;
6740 $("body").css("cursor", o._cursor);
6745 $.ui.plugin.add("draggable", "opacity", {
6746 start: function( event, ui, instance ) {
6747 var t = $( ui.helper ),
6748 o = instance.options;
6749 if (t.css("opacity")) {
6750 o._opacity = t.css("opacity");
6752 t.css("opacity", o.opacity);
6754 stop: function( event, ui, instance ) {
6755 var o = instance.options;
6757 $(ui.helper).css("opacity", o._opacity);
6762 $.ui.plugin.add("draggable", "scroll", {
6763 start: function( event, ui, i ) {
6764 if ( !i.scrollParentNotHidden ) {
6765 i.scrollParentNotHidden = i.helper.scrollParent( false );
6768 if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] && i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) {
6769 i.overflowOffset = i.scrollParentNotHidden.offset();
6772 drag: function( event, ui, i ) {
6776 scrollParent = i.scrollParentNotHidden[ 0 ],
6777 document = i.document[ 0 ];
6779 if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) {
6780 if ( !o.axis || o.axis !== "x" ) {
6781 if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY < o.scrollSensitivity ) {
6782 scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed;
6783 } else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) {
6784 scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed;
6788 if ( !o.axis || o.axis !== "y" ) {
6789 if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX < o.scrollSensitivity ) {
6790 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed;
6791 } else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) {
6792 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed;
6798 if (!o.axis || o.axis !== "x") {
6799 if (event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
6800 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
6801 } else if ($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
6802 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
6806 if (!o.axis || o.axis !== "y") {
6807 if (event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
6808 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
6809 } else if ($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
6810 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
6816 if (scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
6817 $.ui.ddmanager.prepareOffsets(i, event);
6823 $.ui.plugin.add("draggable", "snap", {
6824 start: function( event, ui, i ) {
6828 i.snapElements = [];
6830 $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() {
6833 if (this !== i.element[0]) {
6834 i.snapElements.push({
6836 width: $t.outerWidth(), height: $t.outerHeight(),
6837 top: $o.top, left: $o.left
6843 drag: function( event, ui, inst ) {
6845 var ts, bs, ls, rs, l, r, t, b, i, first,
6847 d = o.snapTolerance,
6848 x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
6849 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
6851 for (i = inst.snapElements.length - 1; i >= 0; i--){
6853 l = inst.snapElements[i].left - inst.margins.left;
6854 r = l + inst.snapElements[i].width;
6855 t = inst.snapElements[i].top - inst.margins.top;
6856 b = t + inst.snapElements[i].height;
6858 if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || !$.contains( inst.snapElements[ i ].item.ownerDocument, inst.snapElements[ i ].item ) ) {
6859 if (inst.snapElements[i].snapping) {
6860 (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
6862 inst.snapElements[i].snapping = false;
6866 if (o.snapMode !== "inner") {
6867 ts = Math.abs(t - y2) <= d;
6868 bs = Math.abs(b - y1) <= d;
6869 ls = Math.abs(l - x2) <= d;
6870 rs = Math.abs(r - x1) <= d;
6872 ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top;
6875 ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top;
6878 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left;
6881 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left;
6885 first = (ts || bs || ls || rs);
6887 if (o.snapMode !== "outer") {
6888 ts = Math.abs(t - y1) <= d;
6889 bs = Math.abs(b - y2) <= d;
6890 ls = Math.abs(l - x1) <= d;
6891 rs = Math.abs(r - x2) <= d;
6893 ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top;
6896 ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top;
6899 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left;
6902 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left;
6906 if (!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) {
6907 (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
6909 inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
6916 $.ui.plugin.add("draggable", "stack", {
6917 start: function( event, ui, instance ) {
6919 o = instance.options,
6920 group = $.makeArray($(o.stack)).sort(function(a, b) {
6921 return (parseInt($(a).css("zIndex"), 10) || 0) - (parseInt($(b).css("zIndex"), 10) || 0);
6924 if (!group.length) { return; }
6926 min = parseInt($(group[0]).css("zIndex"), 10) || 0;
6927 $(group).each(function(i) {
6928 $(this).css("zIndex", min + i);
6930 this.css("zIndex", (min + group.length));
6934 $.ui.plugin.add("draggable", "zIndex", {
6935 start: function( event, ui, instance ) {
6936 var t = $( ui.helper ),
6937 o = instance.options;
6939 if (t.css("zIndex")) {
6940 o._zIndex = t.css("zIndex");
6942 t.css("zIndex", o.zIndex);
6944 stop: function( event, ui, instance ) {
6945 var o = instance.options;
6948 $(ui.helper).css("zIndex", o._zIndex);
6953 var draggable = $.ui.draggable;
6957 * jQuery UI Resizable 1.11.4
6958 * http://jqueryui.com
6960 * Copyright jQuery Foundation and other contributors
6961 * Released under the MIT license.
6962 * http://jquery.org/license
6964 * http://api.jqueryui.com/resizable/
6968 $.widget("ui.resizable", $.ui.mouse, {
6970 widgetEventPrefix: "resize",
6974 animateDuration: "slow",
6975 animateEasing: "swing",
6996 _num: function( value ) {
6997 return parseInt( value, 10 ) || 0;
7000 _isNumber: function( value ) {
7001 return !isNaN( parseInt( value, 10 ) );
7004 _hasScroll: function( el, a ) {
7006 if ( $( el ).css( "overflow" ) === "hidden") {
7010 var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
7013 if ( el[ scroll ] > 0 ) {
7017 // TODO: determine which cases actually cause this to happen
7018 // if the element doesn't have the scroll set, see if it's possible to
7021 has = ( el[ scroll ] > 0 );
7026 _create: function() {
7028 var n, i, handle, axis, hname,
7031 this.element.addClass("ui-resizable");
7034 _aspectRatio: !!(o.aspectRatio),
7035 aspectRatio: o.aspectRatio,
7036 originalElement: this.element,
7037 _proportionallyResizeElements: [],
7038 _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
7041 // Wrap the element if it cannot hold child nodes
7042 if (this.element[0].nodeName.match(/^(canvas|textarea|input|select|button|img)$/i)) {
7045 $("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({
7046 position: this.element.css("position"),
7047 width: this.element.outerWidth(),
7048 height: this.element.outerHeight(),
7049 top: this.element.css("top"),
7050 left: this.element.css("left")
7054 this.element = this.element.parent().data(
7055 "ui-resizable", this.element.resizable( "instance" )
7058 this.elementIsWrapper = true;
7061 marginLeft: this.originalElement.css("marginLeft"),
7062 marginTop: this.originalElement.css("marginTop"),
7063 marginRight: this.originalElement.css("marginRight"),
7064 marginBottom: this.originalElement.css("marginBottom")
7066 this.originalElement.css({
7073 // Prevent Safari textarea resize
7074 this.originalResizeStyle = this.originalElement.css("resize");
7075 this.originalElement.css("resize", "none");
7077 this._proportionallyResizeElements.push( this.originalElement.css({
7084 // avoid IE jump (hard set the margin)
7085 this.originalElement.css({ margin: this.originalElement.css("margin") });
7087 this._proportionallyResize();
7090 this.handles = o.handles ||
7091 ( !$(".ui-resizable-handle", this.element).length ?
7093 n: ".ui-resizable-n",
7094 e: ".ui-resizable-e",
7095 s: ".ui-resizable-s",
7096 w: ".ui-resizable-w",
7097 se: ".ui-resizable-se",
7098 sw: ".ui-resizable-sw",
7099 ne: ".ui-resizable-ne",
7100 nw: ".ui-resizable-nw"
7103 this._handles = $();
7104 if ( this.handles.constructor === String ) {
7106 if ( this.handles === "all") {
7107 this.handles = "n,e,s,w,se,sw,ne,nw";
7110 n = this.handles.split(",");
7113 for (i = 0; i < n.length; i++) {
7115 handle = $.trim(n[i]);
7116 hname = "ui-resizable-" + handle;
7117 axis = $("<div class='ui-resizable-handle " + hname + "'></div>");
7119 axis.css({ zIndex: o.zIndex });
7121 // TODO : What's going on here?
7122 if ("se" === handle) {
7123 axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se");
7126 this.handles[handle] = ".ui-resizable-" + handle;
7127 this.element.append(axis);
7132 this._renderAxis = function(target) {
7134 var i, axis, padPos, padWrapper;
7136 target = target || this.element;
7138 for (i in this.handles) {
7140 if (this.handles[i].constructor === String) {
7141 this.handles[i] = this.element.children( this.handles[ i ] ).first().show();
7142 } else if ( this.handles[ i ].jquery || this.handles[ i ].nodeType ) {
7143 this.handles[ i ] = $( this.handles[ i ] );
7144 this._on( this.handles[ i ], { "mousedown": that._mouseDown });
7147 if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)) {
7149 axis = $(this.handles[i], this.element);
7151 padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
7153 padPos = [ "padding",
7154 /ne|nw|n/.test(i) ? "Top" :
7155 /se|sw|s/.test(i) ? "Bottom" :
7156 /^e$/.test(i) ? "Right" : "Left" ].join("");
7158 target.css(padPos, padWrapper);
7160 this._proportionallyResize();
7163 this._handles = this._handles.add( this.handles[ i ] );
7167 // TODO: make renderAxis a prototype function
7168 this._renderAxis(this.element);
7170 this._handles = this._handles.add( this.element.find( ".ui-resizable-handle" ) );
7171 this._handles.disableSelection();
7173 this._handles.mouseover(function() {
7174 if (!that.resizing) {
7175 if (this.className) {
7176 axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
7178 that.axis = axis && axis[1] ? axis[1] : "se";
7183 this._handles.hide();
7185 .addClass("ui-resizable-autohide")
7186 .mouseenter(function() {
7190 $(this).removeClass("ui-resizable-autohide");
7191 that._handles.show();
7193 .mouseleave(function() {
7197 if (!that.resizing) {
7198 $(this).addClass("ui-resizable-autohide");
7199 that._handles.hide();
7207 _destroy: function() {
7209 this._mouseDestroy();
7212 _destroy = function(exp) {
7214 .removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing")
7215 .removeData("resizable")
7216 .removeData("ui-resizable")
7217 .unbind(".resizable")
7218 .find(".ui-resizable-handle")
7222 // TODO: Unwrap at same DOM position
7223 if (this.elementIsWrapper) {
7224 _destroy(this.element);
7225 wrapper = this.element;
7226 this.originalElement.css({
7227 position: wrapper.css("position"),
7228 width: wrapper.outerWidth(),
7229 height: wrapper.outerHeight(),
7230 top: wrapper.css("top"),
7231 left: wrapper.css("left")
7232 }).insertAfter( wrapper );
7236 this.originalElement.css("resize", this.originalResizeStyle);
7237 _destroy(this.originalElement);
7242 _mouseCapture: function(event) {
7246 for (i in this.handles) {
7247 handle = $(this.handles[i])[0];
7248 if (handle === event.target || $.contains(handle, event.target)) {
7253 return !this.options.disabled && capture;
7256 _mouseStart: function(event) {
7258 var curleft, curtop, cursor,
7262 this.resizing = true;
7264 this._renderProxy();
7266 curleft = this._num(this.helper.css("left"));
7267 curtop = this._num(this.helper.css("top"));
7269 if (o.containment) {
7270 curleft += $(o.containment).scrollLeft() || 0;
7271 curtop += $(o.containment).scrollTop() || 0;
7274 this.offset = this.helper.offset();
7275 this.position = { left: curleft, top: curtop };
7277 this.size = this._helper ? {
7278 width: this.helper.width(),
7279 height: this.helper.height()
7285 this.originalSize = this._helper ? {
7286 width: el.outerWidth(),
7287 height: el.outerHeight()
7294 width: el.outerWidth() - el.width(),
7295 height: el.outerHeight() - el.height()
7298 this.originalPosition = { left: curleft, top: curtop };
7299 this.originalMousePosition = { left: event.pageX, top: event.pageY };
7301 this.aspectRatio = (typeof o.aspectRatio === "number") ?
7303 ((this.originalSize.width / this.originalSize.height) || 1);
7305 cursor = $(".ui-resizable-" + this.axis).css("cursor");
7306 $("body").css("cursor", cursor === "auto" ? this.axis + "-resize" : cursor);
7308 el.addClass("ui-resizable-resizing");
7309 this._propagate("start", event);
7313 _mouseDrag: function(event) {
7316 smp = this.originalMousePosition,
7318 dx = (event.pageX - smp.left) || 0,
7319 dy = (event.pageY - smp.top) || 0,
7320 trigger = this._change[a];
7322 this._updatePrevProperties();
7328 data = trigger.apply(this, [ event, dx, dy ]);
7330 this._updateVirtualBoundaries(event.shiftKey);
7331 if (this._aspectRatio || event.shiftKey) {
7332 data = this._updateRatio(data, event);
7335 data = this._respectSize(data, event);
7337 this._updateCache(data);
7339 this._propagate("resize", event);
7341 props = this._applyChanges();
7343 if ( !this._helper && this._proportionallyResizeElements.length ) {
7344 this._proportionallyResize();
7347 if ( !$.isEmptyObject( props ) ) {
7348 this._updatePrevProperties();
7349 this._trigger( "resize", event, this.ui() );
7350 this._applyChanges();
7356 _mouseStop: function(event) {
7358 this.resizing = false;
7359 var pr, ista, soffseth, soffsetw, s, left, top,
7360 o = this.options, that = this;
7364 pr = this._proportionallyResizeElements;
7365 ista = pr.length && (/textarea/i).test(pr[0].nodeName);
7366 soffseth = ista && this._hasScroll(pr[0], "left") ? 0 : that.sizeDiff.height;
7367 soffsetw = ista ? 0 : that.sizeDiff.width;
7370 width: (that.helper.width() - soffsetw),
7371 height: (that.helper.height() - soffseth)
7373 left = (parseInt(that.element.css("left"), 10) +
7374 (that.position.left - that.originalPosition.left)) || null;
7375 top = (parseInt(that.element.css("top"), 10) +
7376 (that.position.top - that.originalPosition.top)) || null;
7379 this.element.css($.extend(s, { top: top, left: left }));
7382 that.helper.height(that.size.height);
7383 that.helper.width(that.size.width);
7385 if (this._helper && !o.animate) {
7386 this._proportionallyResize();
7390 $("body").css("cursor", "auto");
7392 this.element.removeClass("ui-resizable-resizing");
7394 this._propagate("stop", event);
7397 this.helper.remove();
7404 _updatePrevProperties: function() {
7405 this.prevPosition = {
7406 top: this.position.top,
7407 left: this.position.left
7410 width: this.size.width,
7411 height: this.size.height
7415 _applyChanges: function() {
7418 if ( this.position.top !== this.prevPosition.top ) {
7419 props.top = this.position.top + "px";
7421 if ( this.position.left !== this.prevPosition.left ) {
7422 props.left = this.position.left + "px";
7424 if ( this.size.width !== this.prevSize.width ) {
7425 props.width = this.size.width + "px";
7427 if ( this.size.height !== this.prevSize.height ) {
7428 props.height = this.size.height + "px";
7431 this.helper.css( props );
7436 _updateVirtualBoundaries: function(forceAspectRatio) {
7437 var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
7441 minWidth: this._isNumber(o.minWidth) ? o.minWidth : 0,
7442 maxWidth: this._isNumber(o.maxWidth) ? o.maxWidth : Infinity,
7443 minHeight: this._isNumber(o.minHeight) ? o.minHeight : 0,
7444 maxHeight: this._isNumber(o.maxHeight) ? o.maxHeight : Infinity
7447 if (this._aspectRatio || forceAspectRatio) {
7448 pMinWidth = b.minHeight * this.aspectRatio;
7449 pMinHeight = b.minWidth / this.aspectRatio;
7450 pMaxWidth = b.maxHeight * this.aspectRatio;
7451 pMaxHeight = b.maxWidth / this.aspectRatio;
7453 if (pMinWidth > b.minWidth) {
7454 b.minWidth = pMinWidth;
7456 if (pMinHeight > b.minHeight) {
7457 b.minHeight = pMinHeight;
7459 if (pMaxWidth < b.maxWidth) {
7460 b.maxWidth = pMaxWidth;
7462 if (pMaxHeight < b.maxHeight) {
7463 b.maxHeight = pMaxHeight;
7466 this._vBoundaries = b;
7469 _updateCache: function(data) {
7470 this.offset = this.helper.offset();
7471 if (this._isNumber(data.left)) {
7472 this.position.left = data.left;
7474 if (this._isNumber(data.top)) {
7475 this.position.top = data.top;
7477 if (this._isNumber(data.height)) {
7478 this.size.height = data.height;
7480 if (this._isNumber(data.width)) {
7481 this.size.width = data.width;
7485 _updateRatio: function( data ) {
7487 var cpos = this.position,
7491 if (this._isNumber(data.height)) {
7492 data.width = (data.height * this.aspectRatio);
7493 } else if (this._isNumber(data.width)) {
7494 data.height = (data.width / this.aspectRatio);
7498 data.left = cpos.left + (csize.width - data.width);
7502 data.top = cpos.top + (csize.height - data.height);
7503 data.left = cpos.left + (csize.width - data.width);
7509 _respectSize: function( data ) {
7511 var o = this._vBoundaries,
7513 ismaxw = this._isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width),
7514 ismaxh = this._isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height),
7515 isminw = this._isNumber(data.width) && o.minWidth && (o.minWidth > data.width),
7516 isminh = this._isNumber(data.height) && o.minHeight && (o.minHeight > data.height),
7517 dw = this.originalPosition.left + this.originalSize.width,
7518 dh = this.position.top + this.size.height,
7519 cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
7521 data.width = o.minWidth;
7524 data.height = o.minHeight;
7527 data.width = o.maxWidth;
7530 data.height = o.maxHeight;
7534 data.left = dw - o.minWidth;
7537 data.left = dw - o.maxWidth;
7540 data.top = dh - o.minHeight;
7543 data.top = dh - o.maxHeight;
7546 // Fixing jump error on top/left - bug #2330
7547 if (!data.width && !data.height && !data.left && data.top) {
7549 } else if (!data.width && !data.height && !data.top && data.left) {
7556 _getPaddingPlusBorderDimensions: function( element ) {
7560 element.css( "borderTopWidth" ),
7561 element.css( "borderRightWidth" ),
7562 element.css( "borderBottomWidth" ),
7563 element.css( "borderLeftWidth" )
7566 element.css( "paddingTop" ),
7567 element.css( "paddingRight" ),
7568 element.css( "paddingBottom" ),
7569 element.css( "paddingLeft" )
7572 for ( ; i < 4; i++ ) {
7573 widths[ i ] = ( parseInt( borders[ i ], 10 ) || 0 );
7574 widths[ i ] += ( parseInt( paddings[ i ], 10 ) || 0 );
7578 height: widths[ 0 ] + widths[ 2 ],
7579 width: widths[ 1 ] + widths[ 3 ]
7583 _proportionallyResize: function() {
7585 if (!this._proportionallyResizeElements.length) {
7591 element = this.helper || this.element;
7593 for ( ; i < this._proportionallyResizeElements.length; i++) {
7595 prel = this._proportionallyResizeElements[i];
7597 // TODO: Seems like a bug to cache this.outerDimensions
7598 // considering that we are in a loop.
7599 if (!this.outerDimensions) {
7600 this.outerDimensions = this._getPaddingPlusBorderDimensions( prel );
7604 height: (element.height() - this.outerDimensions.height) || 0,
7605 width: (element.width() - this.outerDimensions.width) || 0
7612 _renderProxy: function() {
7614 var el = this.element, o = this.options;
7615 this.elementOffset = el.offset();
7619 this.helper = this.helper || $("<div style='overflow:hidden;'></div>");
7621 this.helper.addClass(this._helper).css({
7622 width: this.element.outerWidth() - 1,
7623 height: this.element.outerHeight() - 1,
7624 position: "absolute",
7625 left: this.elementOffset.left + "px",
7626 top: this.elementOffset.top + "px",
7627 zIndex: ++o.zIndex //TODO: Don't modify option
7632 .disableSelection();
7635 this.helper = this.element;
7641 e: function(event, dx) {
7642 return { width: this.originalSize.width + dx };
7644 w: function(event, dx) {
7645 var cs = this.originalSize, sp = this.originalPosition;
7646 return { left: sp.left + dx, width: cs.width - dx };
7648 n: function(event, dx, dy) {
7649 var cs = this.originalSize, sp = this.originalPosition;
7650 return { top: sp.top + dy, height: cs.height - dy };
7652 s: function(event, dx, dy) {
7653 return { height: this.originalSize.height + dy };
7655 se: function(event, dx, dy) {
7656 return $.extend(this._change.s.apply(this, arguments),
7657 this._change.e.apply(this, [ event, dx, dy ]));
7659 sw: function(event, dx, dy) {
7660 return $.extend(this._change.s.apply(this, arguments),
7661 this._change.w.apply(this, [ event, dx, dy ]));
7663 ne: function(event, dx, dy) {
7664 return $.extend(this._change.n.apply(this, arguments),
7665 this._change.e.apply(this, [ event, dx, dy ]));
7667 nw: function(event, dx, dy) {
7668 return $.extend(this._change.n.apply(this, arguments),
7669 this._change.w.apply(this, [ event, dx, dy ]));
7673 _propagate: function(n, event) {
7674 $.ui.plugin.call(this, n, [ event, this.ui() ]);
7675 (n !== "resize" && this._trigger(n, event, this.ui()));
7682 originalElement: this.originalElement,
7683 element: this.element,
7684 helper: this.helper,
7685 position: this.position,
7687 originalSize: this.originalSize,
7688 originalPosition: this.originalPosition
7695 * Resizable Extensions
7698 $.ui.plugin.add("resizable", "animate", {
7700 stop: function( event ) {
7701 var that = $(this).resizable( "instance" ),
7703 pr = that._proportionallyResizeElements,
7704 ista = pr.length && (/textarea/i).test(pr[0].nodeName),
7705 soffseth = ista && that._hasScroll(pr[0], "left") ? 0 : that.sizeDiff.height,
7706 soffsetw = ista ? 0 : that.sizeDiff.width,
7707 style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) },
7708 left = (parseInt(that.element.css("left"), 10) +
7709 (that.position.left - that.originalPosition.left)) || null,
7710 top = (parseInt(that.element.css("top"), 10) +
7711 (that.position.top - that.originalPosition.top)) || null;
7713 that.element.animate(
7714 $.extend(style, top && left ? { top: top, left: left } : {}), {
7715 duration: o.animateDuration,
7716 easing: o.animateEasing,
7720 width: parseInt(that.element.css("width"), 10),
7721 height: parseInt(that.element.css("height"), 10),
7722 top: parseInt(that.element.css("top"), 10),
7723 left: parseInt(that.element.css("left"), 10)
7726 if (pr && pr.length) {
7727 $(pr[0]).css({ width: data.width, height: data.height });
7730 // propagating resize, and updating values for each animation step
7731 that._updateCache(data);
7732 that._propagate("resize", event);
7741 $.ui.plugin.add( "resizable", "containment", {
7744 var element, p, co, ch, cw, width, height,
7745 that = $( this ).resizable( "instance" ),
7749 ce = ( oc instanceof $ ) ? oc.get( 0 ) : ( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc;
7755 that.containerElement = $( ce );
7757 if ( /document/.test( oc ) || oc === document ) {
7758 that.containerOffset = {
7762 that.containerPosition = {
7768 element: $( document ),
7771 width: $( document ).width(),
7772 height: $( document ).height() || document.body.parentNode.scrollHeight
7777 $([ "Top", "Right", "Left", "Bottom" ]).each(function( i, name ) {
7778 p[ i ] = that._num( element.css( "padding" + name ) );
7781 that.containerOffset = element.offset();
7782 that.containerPosition = element.position();
7783 that.containerSize = {
7784 height: ( element.innerHeight() - p[ 3 ] ),
7785 width: ( element.innerWidth() - p[ 1 ] )
7788 co = that.containerOffset;
7789 ch = that.containerSize.height;
7790 cw = that.containerSize.width;
7791 width = ( that._hasScroll ( ce, "left" ) ? ce.scrollWidth : cw );
7792 height = ( that._hasScroll ( ce ) ? ce.scrollHeight : ch ) ;
7804 resize: function( event ) {
7805 var woset, hoset, isParent, isOffsetRelative,
7806 that = $( this ).resizable( "instance" ),
7808 co = that.containerOffset,
7810 pRatio = that._aspectRatio || event.shiftKey,
7815 ce = that.containerElement,
7816 continueResize = true;
7818 if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) {
7822 if ( cp.left < ( that._helper ? co.left : 0 ) ) {
7823 that.size.width = that.size.width +
7825 ( that.position.left - co.left ) :
7826 ( that.position.left - cop.left ) );
7829 that.size.height = that.size.width / that.aspectRatio;
7830 continueResize = false;
7832 that.position.left = o.helper ? co.left : 0;
7835 if ( cp.top < ( that._helper ? co.top : 0 ) ) {
7836 that.size.height = that.size.height +
7838 ( that.position.top - co.top ) :
7839 that.position.top );
7842 that.size.width = that.size.height * that.aspectRatio;
7843 continueResize = false;
7845 that.position.top = that._helper ? co.top : 0;
7848 isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 );
7849 isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) );
7851 if ( isParent && isOffsetRelative ) {
7852 that.offset.left = that.parentData.left + that.position.left;
7853 that.offset.top = that.parentData.top + that.position.top;
7855 that.offset.left = that.element.offset().left;
7856 that.offset.top = that.element.offset().top;
7859 woset = Math.abs( that.sizeDiff.width +
7861 that.offset.left - cop.left :
7862 (that.offset.left - co.left)) );
7864 hoset = Math.abs( that.sizeDiff.height +
7866 that.offset.top - cop.top :
7867 (that.offset.top - co.top)) );
7869 if ( woset + that.size.width >= that.parentData.width ) {
7870 that.size.width = that.parentData.width - woset;
7872 that.size.height = that.size.width / that.aspectRatio;
7873 continueResize = false;
7877 if ( hoset + that.size.height >= that.parentData.height ) {
7878 that.size.height = that.parentData.height - hoset;
7880 that.size.width = that.size.height * that.aspectRatio;
7881 continueResize = false;
7885 if ( !continueResize ) {
7886 that.position.left = that.prevPosition.left;
7887 that.position.top = that.prevPosition.top;
7888 that.size.width = that.prevSize.width;
7889 that.size.height = that.prevSize.height;
7894 var that = $( this ).resizable( "instance" ),
7896 co = that.containerOffset,
7897 cop = that.containerPosition,
7898 ce = that.containerElement,
7899 helper = $( that.helper ),
7900 ho = helper.offset(),
7901 w = helper.outerWidth() - that.sizeDiff.width,
7902 h = helper.outerHeight() - that.sizeDiff.height;
7904 if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) {
7906 left: ho.left - cop.left - co.left,
7912 if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) {
7914 left: ho.left - cop.left - co.left,
7922 $.ui.plugin.add("resizable", "alsoResize", {
7925 var that = $(this).resizable( "instance" ),
7928 $(o.alsoResize).each(function() {
7930 el.data("ui-resizable-alsoresize", {
7931 width: parseInt(el.width(), 10), height: parseInt(el.height(), 10),
7932 left: parseInt(el.css("left"), 10), top: parseInt(el.css("top"), 10)
7937 resize: function(event, ui) {
7938 var that = $(this).resizable( "instance" ),
7940 os = that.originalSize,
7941 op = that.originalPosition,
7943 height: (that.size.height - os.height) || 0,
7944 width: (that.size.width - os.width) || 0,
7945 top: (that.position.top - op.top) || 0,
7946 left: (that.position.left - op.left) || 0
7949 $(o.alsoResize).each(function() {
7950 var el = $(this), start = $(this).data("ui-resizable-alsoresize"), style = {},
7951 css = el.parents(ui.originalElement[0]).length ?
7952 [ "width", "height" ] :
7953 [ "width", "height", "top", "left" ];
7955 $.each(css, function(i, prop) {
7956 var sum = (start[prop] || 0) + (delta[prop] || 0);
7957 if (sum && sum >= 0) {
7958 style[prop] = sum || null;
7967 $(this).removeData("resizable-alsoresize");
7971 $.ui.plugin.add("resizable", "ghost", {
7975 var that = $(this).resizable( "instance" ), o = that.options, cs = that.size;
7977 that.ghost = that.originalElement.clone();
7982 position: "relative",
7989 .addClass("ui-resizable-ghost")
7990 .addClass(typeof o.ghost === "string" ? o.ghost : "");
7992 that.ghost.appendTo(that.helper);
7996 resize: function() {
7997 var that = $(this).resizable( "instance" );
8000 position: "relative",
8001 height: that.size.height,
8002 width: that.size.width
8008 var that = $(this).resizable( "instance" );
8009 if (that.ghost && that.helper) {
8010 that.helper.get(0).removeChild(that.ghost.get(0));
8016 $.ui.plugin.add("resizable", "grid", {
8018 resize: function() {
8019 var outerDimensions,
8020 that = $(this).resizable( "instance" ),
8023 os = that.originalSize,
8024 op = that.originalPosition,
8026 grid = typeof o.grid === "number" ? [ o.grid, o.grid ] : o.grid,
8027 gridX = (grid[0] || 1),
8028 gridY = (grid[1] || 1),
8029 ox = Math.round((cs.width - os.width) / gridX) * gridX,
8030 oy = Math.round((cs.height - os.height) / gridY) * gridY,
8031 newWidth = os.width + ox,
8032 newHeight = os.height + oy,
8033 isMaxWidth = o.maxWidth && (o.maxWidth < newWidth),
8034 isMaxHeight = o.maxHeight && (o.maxHeight < newHeight),
8035 isMinWidth = o.minWidth && (o.minWidth > newWidth),
8036 isMinHeight = o.minHeight && (o.minHeight > newHeight);
8053 if (/^(se|s|e)$/.test(a)) {
8054 that.size.width = newWidth;
8055 that.size.height = newHeight;
8056 } else if (/^(ne)$/.test(a)) {
8057 that.size.width = newWidth;
8058 that.size.height = newHeight;
8059 that.position.top = op.top - oy;
8060 } else if (/^(sw)$/.test(a)) {
8061 that.size.width = newWidth;
8062 that.size.height = newHeight;
8063 that.position.left = op.left - ox;
8065 if ( newHeight - gridY <= 0 || newWidth - gridX <= 0) {
8066 outerDimensions = that._getPaddingPlusBorderDimensions( this );
8069 if ( newHeight - gridY > 0 ) {
8070 that.size.height = newHeight;
8071 that.position.top = op.top - oy;
8073 newHeight = gridY - outerDimensions.height;
8074 that.size.height = newHeight;
8075 that.position.top = op.top + os.height - newHeight;
8077 if ( newWidth - gridX > 0 ) {
8078 that.size.width = newWidth;
8079 that.position.left = op.left - ox;
8081 newWidth = gridX - outerDimensions.width;
8082 that.size.width = newWidth;
8083 that.position.left = op.left + os.width - newWidth;
8090 var resizable = $.ui.resizable;
8094 * jQuery UI Dialog 1.11.4
8095 * http://jqueryui.com
8097 * Copyright jQuery Foundation and other contributors
8098 * Released under the MIT license.
8099 * http://jquery.org/license
8101 * http://api.jqueryui.com/dialog/
8105 var dialog = $.widget( "ui.dialog", {
8111 closeOnEscape: true,
8127 // Ensure the titlebar is always visible
8128 using: function( pos ) {
8129 var topOffset = $( this ).css( pos ).offset().top;
8130 if ( topOffset < 0 ) {
8131 $( this ).css( "top", pos.top - topOffset );
8153 sizeRelatedOptions: {
8163 resizableRelatedOptions: {
8170 _create: function() {
8171 this.originalCss = {
8172 display: this.element[ 0 ].style.display,
8173 width: this.element[ 0 ].style.width,
8174 minHeight: this.element[ 0 ].style.minHeight,
8175 maxHeight: this.element[ 0 ].style.maxHeight,
8176 height: this.element[ 0 ].style.height
8178 this.originalPosition = {
8179 parent: this.element.parent(),
8180 index: this.element.parent().children().index( this.element )
8182 this.originalTitle = this.element.attr( "title" );
8183 this.options.title = this.options.title || this.originalTitle;
8185 this._createWrapper();
8189 .removeAttr( "title" )
8190 .addClass( "ui-dialog-content ui-widget-content" )
8191 .appendTo( this.uiDialog );
8193 this._createTitlebar();
8194 this._createButtonPane();
8196 if ( this.options.draggable && $.fn.draggable ) {
8197 this._makeDraggable();
8199 if ( this.options.resizable && $.fn.resizable ) {
8200 this._makeResizable();
8203 this._isOpen = false;
8209 if ( this.options.autoOpen ) {
8214 _appendTo: function() {
8215 var element = this.options.appendTo;
8216 if ( element && (element.jquery || element.nodeType) ) {
8217 return $( element );
8219 return this.document.find( element || "body" ).eq( 0 );
8222 _destroy: function() {
8224 originalPosition = this.originalPosition;
8226 this._untrackInstance();
8227 this._destroyOverlay();
8231 .removeClass( "ui-dialog-content ui-widget-content" )
8232 .css( this.originalCss )
8233 // Without detaching first, the following becomes really slow
8236 this.uiDialog.stop( true, true ).remove();
8238 if ( this.originalTitle ) {
8239 this.element.attr( "title", this.originalTitle );
8242 next = originalPosition.parent.children().eq( originalPosition.index );
8243 // Don't try to place the dialog next to itself (#8613)
8244 if ( next.length && next[ 0 ] !== this.element[ 0 ] ) {
8245 next.before( this.element );
8247 originalPosition.parent.append( this.element );
8251 widget: function() {
8252 return this.uiDialog;
8258 close: function( event ) {
8262 if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) {
8266 this._isOpen = false;
8267 this._focusedElement = null;
8268 this._destroyOverlay();
8269 this._untrackInstance();
8271 if ( !this.opener.filter( ":focusable" ).focus().length ) {
8274 // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
8276 activeElement = this.document[ 0 ].activeElement;
8278 // Support: IE9, IE10
8279 // If the <body> is blurred, IE will switch windows, see #4520
8280 if ( activeElement && activeElement.nodeName.toLowerCase() !== "body" ) {
8282 // Hiding a focused element doesn't trigger blur in WebKit
8283 // so in case we have nothing to focus on, explicitly blur the active element
8284 // https://bugs.webkit.org/show_bug.cgi?id=47182
8285 $( activeElement ).blur();
8287 } catch ( error ) {}
8290 this._hide( this.uiDialog, this.options.hide, function() {
8291 that._trigger( "close", event );
8295 isOpen: function() {
8296 return this._isOpen;
8299 moveToTop: function() {
8303 _moveToTop: function( event, silent ) {
8305 zIndices = this.uiDialog.siblings( ".ui-front:visible" ).map(function() {
8306 return +$( this ).css( "z-index" );
8308 zIndexMax = Math.max.apply( null, zIndices );
8310 if ( zIndexMax >= +this.uiDialog.css( "z-index" ) ) {
8311 this.uiDialog.css( "z-index", zIndexMax + 1 );
8315 if ( moved && !silent ) {
8316 this._trigger( "focus", event );
8323 if ( this._isOpen ) {
8324 if ( this._moveToTop() ) {
8325 this._focusTabbable();
8330 this._isOpen = true;
8331 this.opener = $( this.document[ 0 ].activeElement );
8335 this._createOverlay();
8336 this._moveToTop( null, true );
8338 // Ensure the overlay is moved to the top with the dialog, but only when
8339 // opening. The overlay shouldn't move after the dialog is open so that
8340 // modeless dialogs opened after the modal dialog stack properly.
8341 if ( this.overlay ) {
8342 this.overlay.css( "z-index", this.uiDialog.css( "z-index" ) - 1 );
8345 this._show( this.uiDialog, this.options.show, function() {
8346 that._focusTabbable();
8347 that._trigger( "focus" );
8350 // Track the dialog immediately upon openening in case a focus event
8351 // somehow occurs outside of the dialog before an element inside the
8352 // dialog is focused (#10152)
8353 this._makeFocusTarget();
8355 this._trigger( "open" );
8358 _focusTabbable: function() {
8359 // Set focus to the first match:
8360 // 1. An element that was focused previously
8361 // 2. First element inside the dialog matching [autofocus]
8362 // 3. Tabbable element inside the content element
8363 // 4. Tabbable element inside the buttonpane
8364 // 5. The close button
8365 // 6. The dialog itself
8366 var hasFocus = this._focusedElement;
8368 hasFocus = this.element.find( "[autofocus]" );
8370 if ( !hasFocus.length ) {
8371 hasFocus = this.element.find( ":tabbable" );
8373 if ( !hasFocus.length ) {
8374 hasFocus = this.uiDialogButtonPane.find( ":tabbable" );
8376 if ( !hasFocus.length ) {
8377 hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" );
8379 if ( !hasFocus.length ) {
8380 hasFocus = this.uiDialog;
8382 hasFocus.eq( 0 ).focus();
8385 _keepFocus: function( event ) {
8386 function checkFocus() {
8387 var activeElement = this.document[0].activeElement,
8388 isActive = this.uiDialog[0] === activeElement ||
8389 $.contains( this.uiDialog[0], activeElement );
8391 this._focusTabbable();
8394 event.preventDefault();
8395 checkFocus.call( this );
8397 // IE <= 8 doesn't prevent moving focus even with event.preventDefault()
8398 // so we check again later
8399 this._delay( checkFocus );
8402 _createWrapper: function() {
8403 this.uiDialog = $("<div>")
8404 .addClass( "ui-dialog ui-widget ui-widget-content ui-corner-all ui-front " +
8405 this.options.dialogClass )
8408 // Setting tabIndex makes the div focusable
8412 .appendTo( this._appendTo() );
8414 this._on( this.uiDialog, {
8415 keydown: function( event ) {
8416 if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
8417 event.keyCode === $.ui.keyCode.ESCAPE ) {
8418 event.preventDefault();
8419 this.close( event );
8423 // prevent tabbing out of dialogs
8424 if ( event.keyCode !== $.ui.keyCode.TAB || event.isDefaultPrevented() ) {
8427 var tabbables = this.uiDialog.find( ":tabbable" ),
8428 first = tabbables.filter( ":first" ),
8429 last = tabbables.filter( ":last" );
8431 if ( ( event.target === last[0] || event.target === this.uiDialog[0] ) && !event.shiftKey ) {
8432 this._delay(function() {
8435 event.preventDefault();
8436 } else if ( ( event.target === first[0] || event.target === this.uiDialog[0] ) && event.shiftKey ) {
8437 this._delay(function() {
8440 event.preventDefault();
8443 mousedown: function( event ) {
8444 if ( this._moveToTop( event ) ) {
8445 this._focusTabbable();
8450 // We assume that any existing aria-describedby attribute means
8451 // that the dialog content is marked up properly
8452 // otherwise we brute force the content as the description
8453 if ( !this.element.find( "[aria-describedby]" ).length ) {
8454 this.uiDialog.attr({
8455 "aria-describedby": this.element.uniqueId().attr( "id" )
8460 _createTitlebar: function() {
8463 this.uiDialogTitlebar = $( "<div>" )
8464 .addClass( "ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix" )
8465 .prependTo( this.uiDialog );
8466 this._on( this.uiDialogTitlebar, {
8467 mousedown: function( event ) {
8468 // Don't prevent click on close button (#8838)
8469 // Focusing a dialog that is partially scrolled out of view
8470 // causes the browser to scroll it into view, preventing the click event
8471 if ( !$( event.target ).closest( ".ui-dialog-titlebar-close" ) ) {
8472 // Dialog isn't getting focus when dragging (#8063)
8473 this.uiDialog.focus();
8479 // Use type="button" to prevent enter keypresses in textboxes from closing the
8480 // dialog in IE (#9312)
8481 this.uiDialogTitlebarClose = $( "<button type='button'></button>" )
8483 label: this.options.closeText,
8485 primary: "ui-icon-closethick"
8489 .addClass( "ui-dialog-titlebar-close" )
8490 .appendTo( this.uiDialogTitlebar );
8491 this._on( this.uiDialogTitlebarClose, {
8492 click: function( event ) {
8493 event.preventDefault();
8494 this.close( event );
8498 uiDialogTitle = $( "<span>" )
8500 .addClass( "ui-dialog-title" )
8501 .prependTo( this.uiDialogTitlebar );
8502 this._title( uiDialogTitle );
8504 this.uiDialog.attr({
8505 "aria-labelledby": uiDialogTitle.attr( "id" )
8509 _title: function( title ) {
8510 if ( !this.options.title ) {
8511 title.html( " " );
8513 title.text( this.options.title );
8516 _createButtonPane: function() {
8517 this.uiDialogButtonPane = $( "<div>" )
8518 .addClass( "ui-dialog-buttonpane ui-widget-content ui-helper-clearfix" );
8520 this.uiButtonSet = $( "<div>" )
8521 .addClass( "ui-dialog-buttonset" )
8522 .appendTo( this.uiDialogButtonPane );
8524 this._createButtons();
8527 _createButtons: function() {
8529 buttons = this.options.buttons;
8531 // if we already have a button pane, remove it
8532 this.uiDialogButtonPane.remove();
8533 this.uiButtonSet.empty();
8535 if ( $.isEmptyObject( buttons ) || ($.isArray( buttons ) && !buttons.length) ) {
8536 this.uiDialog.removeClass( "ui-dialog-buttons" );
8540 $.each( buttons, function( name, props ) {
8541 var click, buttonOptions;
8542 props = $.isFunction( props ) ?
8543 { click: props, text: name } :
8545 // Default to a non-submitting button
8546 props = $.extend( { type: "button" }, props );
8547 // Change the context for the click callback to be the main element
8548 click = props.click;
8549 props.click = function() {
8550 click.apply( that.element[ 0 ], arguments );
8554 text: props.showText
8557 delete props.showText;
8558 $( "<button></button>", props )
8559 .button( buttonOptions )
8560 .appendTo( that.uiButtonSet );
8562 this.uiDialog.addClass( "ui-dialog-buttons" );
8563 this.uiDialogButtonPane.appendTo( this.uiDialog );
8566 _makeDraggable: function() {
8568 options = this.options;
8570 function filteredUi( ui ) {
8572 position: ui.position,
8577 this.uiDialog.draggable({
8578 cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
8579 handle: ".ui-dialog-titlebar",
8580 containment: "document",
8581 start: function( event, ui ) {
8582 $( this ).addClass( "ui-dialog-dragging" );
8583 that._blockFrames();
8584 that._trigger( "dragStart", event, filteredUi( ui ) );
8586 drag: function( event, ui ) {
8587 that._trigger( "drag", event, filteredUi( ui ) );
8589 stop: function( event, ui ) {
8590 var left = ui.offset.left - that.document.scrollLeft(),
8591 top = ui.offset.top - that.document.scrollTop();
8593 options.position = {
8595 at: "left" + (left >= 0 ? "+" : "") + left + " " +
8596 "top" + (top >= 0 ? "+" : "") + top,
8599 $( this ).removeClass( "ui-dialog-dragging" );
8600 that._unblockFrames();
8601 that._trigger( "dragStop", event, filteredUi( ui ) );
8606 _makeResizable: function() {
8608 options = this.options,
8609 handles = options.resizable,
8610 // .ui-resizable has position: relative defined in the stylesheet
8611 // but dialogs have to use absolute or fixed positioning
8612 position = this.uiDialog.css("position"),
8613 resizeHandles = typeof handles === "string" ?
8615 "n,e,s,w,se,sw,ne,nw";
8617 function filteredUi( ui ) {
8619 originalPosition: ui.originalPosition,
8620 originalSize: ui.originalSize,
8621 position: ui.position,
8626 this.uiDialog.resizable({
8627 cancel: ".ui-dialog-content",
8628 containment: "document",
8629 alsoResize: this.element,
8630 maxWidth: options.maxWidth,
8631 maxHeight: options.maxHeight,
8632 minWidth: options.minWidth,
8633 minHeight: this._minHeight(),
8634 handles: resizeHandles,
8635 start: function( event, ui ) {
8636 $( this ).addClass( "ui-dialog-resizing" );
8637 that._blockFrames();
8638 that._trigger( "resizeStart", event, filteredUi( ui ) );
8640 resize: function( event, ui ) {
8641 that._trigger( "resize", event, filteredUi( ui ) );
8643 stop: function( event, ui ) {
8644 var offset = that.uiDialog.offset(),
8645 left = offset.left - that.document.scrollLeft(),
8646 top = offset.top - that.document.scrollTop();
8648 options.height = that.uiDialog.height();
8649 options.width = that.uiDialog.width();
8650 options.position = {
8652 at: "left" + (left >= 0 ? "+" : "") + left + " " +
8653 "top" + (top >= 0 ? "+" : "") + top,
8656 $( this ).removeClass( "ui-dialog-resizing" );
8657 that._unblockFrames();
8658 that._trigger( "resizeStop", event, filteredUi( ui ) );
8661 .css( "position", position );
8664 _trackFocus: function() {
8665 this._on( this.widget(), {
8666 focusin: function( event ) {
8667 this._makeFocusTarget();
8668 this._focusedElement = $( event.target );
8673 _makeFocusTarget: function() {
8674 this._untrackInstance();
8675 this._trackingInstances().unshift( this );
8678 _untrackInstance: function() {
8679 var instances = this._trackingInstances(),
8680 exists = $.inArray( this, instances );
8681 if ( exists !== -1 ) {
8682 instances.splice( exists, 1 );
8686 _trackingInstances: function() {
8687 var instances = this.document.data( "ui-dialog-instances" );
8690 this.document.data( "ui-dialog-instances", instances );
8695 _minHeight: function() {
8696 var options = this.options;
8698 return options.height === "auto" ?
8700 Math.min( options.minHeight, options.height );
8703 _position: function() {
8704 // Need to show the dialog to get the actual offset in the position plugin
8705 var isVisible = this.uiDialog.is( ":visible" );
8707 this.uiDialog.show();
8709 this.uiDialog.position( this.options.position );
8711 this.uiDialog.hide();
8715 _setOptions: function( options ) {
8718 resizableOptions = {};
8720 $.each( options, function( key, value ) {
8721 that._setOption( key, value );
8723 if ( key in that.sizeRelatedOptions ) {
8726 if ( key in that.resizableRelatedOptions ) {
8727 resizableOptions[ key ] = value;
8735 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
8736 this.uiDialog.resizable( "option", resizableOptions );
8740 _setOption: function( key, value ) {
8741 var isDraggable, isResizable,
8742 uiDialog = this.uiDialog;
8744 if ( key === "dialogClass" ) {
8746 .removeClass( this.options.dialogClass )
8750 if ( key === "disabled" ) {
8754 this._super( key, value );
8756 if ( key === "appendTo" ) {
8757 this.uiDialog.appendTo( this._appendTo() );
8760 if ( key === "buttons" ) {
8761 this._createButtons();
8764 if ( key === "closeText" ) {
8765 this.uiDialogTitlebarClose.button({
8766 // Ensure that we always pass a string
8771 if ( key === "draggable" ) {
8772 isDraggable = uiDialog.is( ":data(ui-draggable)" );
8773 if ( isDraggable && !value ) {
8774 uiDialog.draggable( "destroy" );
8777 if ( !isDraggable && value ) {
8778 this._makeDraggable();
8782 if ( key === "position" ) {
8786 if ( key === "resizable" ) {
8787 // currently resizable, becoming non-resizable
8788 isResizable = uiDialog.is( ":data(ui-resizable)" );
8789 if ( isResizable && !value ) {
8790 uiDialog.resizable( "destroy" );
8793 // currently resizable, changing handles
8794 if ( isResizable && typeof value === "string" ) {
8795 uiDialog.resizable( "option", "handles", value );
8798 // currently non-resizable, becoming resizable
8799 if ( !isResizable && value !== false ) {
8800 this._makeResizable();
8804 if ( key === "title" ) {
8805 this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) );
8810 // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
8811 // divs will both have width and height set, so we need to reset them
8812 var nonContentHeight, minContentHeight, maxContentHeight,
8813 options = this.options;
8815 // Reset content sizing
8816 this.element.show().css({
8823 if ( options.minWidth > options.width ) {
8824 options.width = options.minWidth;
8827 // reset wrapper sizing
8828 // determine the height of all the non-content elements
8829 nonContentHeight = this.uiDialog.css({
8831 width: options.width
8834 minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
8835 maxContentHeight = typeof options.maxHeight === "number" ?
8836 Math.max( 0, options.maxHeight - nonContentHeight ) :
8839 if ( options.height === "auto" ) {
8841 minHeight: minContentHeight,
8842 maxHeight: maxContentHeight,
8846 this.element.height( Math.max( 0, options.height - nonContentHeight ) );
8849 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
8850 this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
8854 _blockFrames: function() {
8855 this.iframeBlocks = this.document.find( "iframe" ).map(function() {
8856 var iframe = $( this );
8860 position: "absolute",
8861 width: iframe.outerWidth(),
8862 height: iframe.outerHeight()
8864 .appendTo( iframe.parent() )
8865 .offset( iframe.offset() )[0];
8869 _unblockFrames: function() {
8870 if ( this.iframeBlocks ) {
8871 this.iframeBlocks.remove();
8872 delete this.iframeBlocks;
8876 _allowInteraction: function( event ) {
8877 if ( $( event.target ).closest( ".ui-dialog" ).length ) {
8881 // TODO: Remove hack when datepicker implements
8882 // the .ui-front logic (#8989)
8883 return !!$( event.target ).closest( ".ui-datepicker" ).length;
8886 _createOverlay: function() {
8887 if ( !this.options.modal ) {
8891 // We use a delay in case the overlay is created from an
8892 // event that we're going to be cancelling (#2804)
8893 var isOpening = true;
8894 this._delay(function() {
8898 if ( !this.document.data( "ui-dialog-overlays" ) ) {
8900 // Prevent use of anchors and inputs
8901 // Using _on() for an event handler shared across many instances is
8902 // safe because the dialogs stack and must be closed in reverse order
8903 this._on( this.document, {
8904 focusin: function( event ) {
8909 if ( !this._allowInteraction( event ) ) {
8910 event.preventDefault();
8911 this._trackingInstances()[ 0 ]._focusTabbable();
8917 this.overlay = $( "<div>" )
8918 .addClass( "ui-widget-overlay ui-front" )
8919 .appendTo( this._appendTo() );
8920 this._on( this.overlay, {
8921 mousedown: "_keepFocus"
8923 this.document.data( "ui-dialog-overlays",
8924 (this.document.data( "ui-dialog-overlays" ) || 0) + 1 );
8927 _destroyOverlay: function() {
8928 if ( !this.options.modal ) {
8932 if ( this.overlay ) {
8933 var overlays = this.document.data( "ui-dialog-overlays" ) - 1;
8937 .unbind( "focusin" )
8938 .removeData( "ui-dialog-overlays" );
8940 this.document.data( "ui-dialog-overlays", overlays );
8943 this.overlay.remove();
8944 this.overlay = null;
8951 * jQuery UI Droppable 1.11.4
8952 * http://jqueryui.com
8954 * Copyright jQuery Foundation and other contributors
8955 * Released under the MIT license.
8956 * http://jquery.org/license
8958 * http://api.jqueryui.com/droppable/
8962 $.widget( "ui.droppable", {
8964 widgetEventPrefix: "drop",
8972 tolerance: "intersect",
8981 _create: function() {
8987 this.isover = false;
8990 this.accept = $.isFunction( accept ) ? accept : function( d ) {
8991 return d.is( accept );
8994 this.proportions = function( /* valueToWrite */ ) {
8995 if ( arguments.length ) {
8996 // Store the droppable's proportions
8997 proportions = arguments[ 0 ];
8999 // Retrieve or derive the droppable's proportions
9000 return proportions ?
9003 width: this.element[ 0 ].offsetWidth,
9004 height: this.element[ 0 ].offsetHeight
9009 this._addToManager( o.scope );
9011 o.addClasses && this.element.addClass( "ui-droppable" );
9015 _addToManager: function( scope ) {
9016 // Add the reference and positions to the manager
9017 $.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || [];
9018 $.ui.ddmanager.droppables[ scope ].push( this );
9021 _splice: function( drop ) {
9023 for ( ; i < drop.length; i++ ) {
9024 if ( drop[ i ] === this ) {
9025 drop.splice( i, 1 );
9030 _destroy: function() {
9031 var drop = $.ui.ddmanager.droppables[ this.options.scope ];
9033 this._splice( drop );
9035 this.element.removeClass( "ui-droppable ui-droppable-disabled" );
9038 _setOption: function( key, value ) {
9040 if ( key === "accept" ) {
9041 this.accept = $.isFunction( value ) ? value : function( d ) {
9042 return d.is( value );
9044 } else if ( key === "scope" ) {
9045 var drop = $.ui.ddmanager.droppables[ this.options.scope ];
9047 this._splice( drop );
9048 this._addToManager( value );
9051 this._super( key, value );
9054 _activate: function( event ) {
9055 var draggable = $.ui.ddmanager.current;
9056 if ( this.options.activeClass ) {
9057 this.element.addClass( this.options.activeClass );
9060 this._trigger( "activate", event, this.ui( draggable ) );
9064 _deactivate: function( event ) {
9065 var draggable = $.ui.ddmanager.current;
9066 if ( this.options.activeClass ) {
9067 this.element.removeClass( this.options.activeClass );
9070 this._trigger( "deactivate", event, this.ui( draggable ) );
9074 _over: function( event ) {
9076 var draggable = $.ui.ddmanager.current;
9078 // Bail if draggable and droppable are same element
9079 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
9083 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
9084 if ( this.options.hoverClass ) {
9085 this.element.addClass( this.options.hoverClass );
9087 this._trigger( "over", event, this.ui( draggable ) );
9092 _out: function( event ) {
9094 var draggable = $.ui.ddmanager.current;
9096 // Bail if draggable and droppable are same element
9097 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
9101 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
9102 if ( this.options.hoverClass ) {
9103 this.element.removeClass( this.options.hoverClass );
9105 this._trigger( "out", event, this.ui( draggable ) );
9110 _drop: function( event, custom ) {
9112 var draggable = custom || $.ui.ddmanager.current,
9113 childrenIntersection = false;
9115 // Bail if draggable and droppable are same element
9116 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
9120 this.element.find( ":data(ui-droppable)" ).not( ".ui-draggable-dragging" ).each(function() {
9121 var inst = $( this ).droppable( "instance" );
9123 inst.options.greedy &&
9124 !inst.options.disabled &&
9125 inst.options.scope === draggable.options.scope &&
9126 inst.accept.call( inst.element[ 0 ], ( draggable.currentItem || draggable.element ) ) &&
9127 $.ui.intersect( draggable, $.extend( inst, { offset: inst.element.offset() } ), inst.options.tolerance, event )
9128 ) { childrenIntersection = true; return false; }
9130 if ( childrenIntersection ) {
9134 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
9135 if ( this.options.activeClass ) {
9136 this.element.removeClass( this.options.activeClass );
9138 if ( this.options.hoverClass ) {
9139 this.element.removeClass( this.options.hoverClass );
9141 this._trigger( "drop", event, this.ui( draggable ) );
9142 return this.element;
9151 draggable: ( c.currentItem || c.element ),
9153 position: c.position,
9154 offset: c.positionAbs
9160 $.ui.intersect = (function() {
9161 function isOverAxis( x, reference, size ) {
9162 return ( x >= reference ) && ( x < ( reference + size ) );
9165 return function( draggable, droppable, toleranceMode, event ) {
9167 if ( !droppable.offset ) {
9171 var x1 = ( draggable.positionAbs || draggable.position.absolute ).left + draggable.margins.left,
9172 y1 = ( draggable.positionAbs || draggable.position.absolute ).top + draggable.margins.top,
9173 x2 = x1 + draggable.helperProportions.width,
9174 y2 = y1 + draggable.helperProportions.height,
9175 l = droppable.offset.left,
9176 t = droppable.offset.top,
9177 r = l + droppable.proportions().width,
9178 b = t + droppable.proportions().height;
9180 switch ( toleranceMode ) {
9182 return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b );
9184 return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half
9185 x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half
9186 t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half
9187 y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half
9189 return isOverAxis( event.pageY, t, droppable.proportions().height ) && isOverAxis( event.pageX, l, droppable.proportions().width );
9192 ( y1 >= t && y1 <= b ) || // Top edge touching
9193 ( y2 >= t && y2 <= b ) || // Bottom edge touching
9194 ( y1 < t && y2 > b ) // Surrounded vertically
9196 ( x1 >= l && x1 <= r ) || // Left edge touching
9197 ( x2 >= l && x2 <= r ) || // Right edge touching
9198 ( x1 < l && x2 > r ) // Surrounded horizontally
9207 This manager tracks offsets of draggables and droppables
9211 droppables: { "default": [] },
9212 prepareOffsets: function( t, event ) {
9215 m = $.ui.ddmanager.droppables[ t.options.scope ] || [],
9216 type = event ? event.type : null, // workaround for #2317
9217 list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack();
9219 droppablesLoop: for ( i = 0; i < m.length; i++ ) {
9221 // No disabled and non-accepted
9222 if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ], ( t.currentItem || t.element ) ) ) ) {
9226 // Filter out elements in the current dragged item
9227 for ( j = 0; j < list.length; j++ ) {
9228 if ( list[ j ] === m[ i ].element[ 0 ] ) {
9229 m[ i ].proportions().height = 0;
9230 continue droppablesLoop;
9234 m[ i ].visible = m[ i ].element.css( "display" ) !== "none";
9235 if ( !m[ i ].visible ) {
9239 // Activate the droppable if used directly from draggables
9240 if ( type === "mousedown" ) {
9241 m[ i ]._activate.call( m[ i ], event );
9244 m[ i ].offset = m[ i ].element.offset();
9245 m[ i ].proportions({ width: m[ i ].element[ 0 ].offsetWidth, height: m[ i ].element[ 0 ].offsetHeight });
9250 drop: function( draggable, event ) {
9252 var dropped = false;
9253 // Create a copy of the droppables in case the list changes during the drop (#9116)
9254 $.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() {
9256 if ( !this.options ) {
9259 if ( !this.options.disabled && this.visible && $.ui.intersect( draggable, this, this.options.tolerance, event ) ) {
9260 dropped = this._drop.call( this, event ) || dropped;
9263 if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
9265 this.isover = false;
9266 this._deactivate.call( this, event );
9273 dragStart: function( draggable, event ) {
9274 // Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003)
9275 draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() {
9276 if ( !draggable.options.refreshPositions ) {
9277 $.ui.ddmanager.prepareOffsets( draggable, event );
9281 drag: function( draggable, event ) {
9283 // If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
9284 if ( draggable.options.refreshPositions ) {
9285 $.ui.ddmanager.prepareOffsets( draggable, event );
9288 // Run through all droppables and check their positions based on specific tolerance options
9289 $.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() {
9291 if ( this.options.disabled || this.greedyChild || !this.visible ) {
9295 var parentInstance, scope, parent,
9296 intersects = $.ui.intersect( draggable, this, this.options.tolerance, event ),
9297 c = !intersects && this.isover ? "isout" : ( intersects && !this.isover ? "isover" : null );
9302 if ( this.options.greedy ) {
9303 // find droppable parents with same scope
9304 scope = this.options.scope;
9305 parent = this.element.parents( ":data(ui-droppable)" ).filter(function() {
9306 return $( this ).droppable( "instance" ).options.scope === scope;
9309 if ( parent.length ) {
9310 parentInstance = $( parent[ 0 ] ).droppable( "instance" );
9311 parentInstance.greedyChild = ( c === "isover" );
9315 // we just moved into a greedy child
9316 if ( parentInstance && c === "isover" ) {
9317 parentInstance.isover = false;
9318 parentInstance.isout = true;
9319 parentInstance._out.call( parentInstance, event );
9323 this[c === "isout" ? "isover" : "isout"] = false;
9324 this[c === "isover" ? "_over" : "_out"].call( this, event );
9326 // we just moved out of a greedy child
9327 if ( parentInstance && c === "isout" ) {
9328 parentInstance.isout = false;
9329 parentInstance.isover = true;
9330 parentInstance._over.call( parentInstance, event );
9335 dragStop: function( draggable, event ) {
9336 draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" );
9337 // Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003)
9338 if ( !draggable.options.refreshPositions ) {
9339 $.ui.ddmanager.prepareOffsets( draggable, event );
9344 var droppable = $.ui.droppable;
9348 * jQuery UI Effects 1.11.4
9349 * http://jqueryui.com
9351 * Copyright jQuery Foundation and other contributors
9352 * Released under the MIT license.
9353 * http://jquery.org/license
9355 * http://api.jqueryui.com/category/effects-core/
9359 var dataSpace = "ui-effects-",
9361 // Create a local jQuery because jQuery Color relies on it and the
9362 // global may not exist with AMD and a custom build (#10199)
9370 * jQuery Color Animations v2.1.2
9371 * https://github.com/jquery/jquery-color
9373 * Copyright 2014 jQuery Foundation and other contributors
9374 * Released under the MIT license.
9375 * http://jquery.org/license
9377 * Date: Wed Jan 16 08:47:09 2013 -0600
9379 (function( jQuery, undefined ) {
9381 var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
9383 // plusequals test for += 100 -= 100
9384 rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
9385 // a set of RE's that can match strings and generate color tuples.
9387 re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
9388 parse: function( execResult ) {
9397 re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
9398 parse: function( execResult ) {
9400 execResult[ 1 ] * 2.55,
9401 execResult[ 2 ] * 2.55,
9402 execResult[ 3 ] * 2.55,
9407 // this regex ignores A-F because it's compared against an already lowercased string
9408 re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
9409 parse: function( execResult ) {
9411 parseInt( execResult[ 1 ], 16 ),
9412 parseInt( execResult[ 2 ], 16 ),
9413 parseInt( execResult[ 3 ], 16 )
9417 // this regex ignores A-F because it's compared against an already lowercased string
9418 re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
9419 parse: function( execResult ) {
9421 parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
9422 parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
9423 parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
9427 re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
9429 parse: function( execResult ) {
9432 execResult[ 2 ] / 100,
9433 execResult[ 3 ] / 100,
9440 color = jQuery.Color = function( color, green, blue, alpha ) {
9441 return new jQuery.Color.fn.parse( color, green, blue, alpha );
9491 support = color.support = {},
9493 // element for support tests
9494 supportElem = jQuery( "<p>" )[ 0 ],
9496 // colors = jQuery.Color.names
9499 // local aliases of functions called often
9502 // determine rgba support immediately
9503 supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
9504 support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
9506 // define cache name and alpha properties
9507 // for rgba and hsla spaces
9508 each( spaces, function( spaceName, space ) {
9509 space.cache = "_" + spaceName;
9510 space.props.alpha = {
9517 function clamp( value, prop, allowEmpty ) {
9518 var type = propTypes[ prop.type ] || {};
9520 if ( value == null ) {
9521 return (allowEmpty || !prop.def) ? null : prop.def;
9524 // ~~ is an short way of doing floor for positive numbers
9525 value = type.floor ? ~~value : parseFloat( value );
9527 // IE will pass in empty strings as value for alpha,
9528 // which will hit this case
9529 if ( isNaN( value ) ) {
9534 // we add mod before modding to make sure that negatives values
9535 // get converted properly: -10 -> 350
9536 return (value + type.mod) % type.mod;
9539 // for now all property types without mod have min and max
9540 return 0 > value ? 0 : type.max < value ? type.max : value;
9543 function stringParse( string ) {
9545 rgba = inst._rgba = [];
9547 string = string.toLowerCase();
9549 each( stringParsers, function( i, parser ) {
9551 match = parser.re.exec( string ),
9552 values = match && parser.parse( match ),
9553 spaceName = parser.space || "rgba";
9556 parsed = inst[ spaceName ]( values );
9558 // if this was an rgba parse the assignment might happen twice
9560 inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
9561 rgba = inst._rgba = parsed._rgba;
9563 // exit each( stringParsers ) here because we matched
9568 // Found a stringParser that handled it
9569 if ( rgba.length ) {
9571 // if this came from a parsed string, force "transparent" when alpha is 0
9572 // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
9573 if ( rgba.join() === "0,0,0,0" ) {
9574 jQuery.extend( rgba, colors.transparent );
9580 return colors[ string ];
9583 color.fn = jQuery.extend( color.prototype, {
9584 parse: function( red, green, blue, alpha ) {
9585 if ( red === undefined ) {
9586 this._rgba = [ null, null, null, null ];
9589 if ( red.jquery || red.nodeType ) {
9590 red = jQuery( red ).css( green );
9595 type = jQuery.type( red ),
9596 rgba = this._rgba = [];
9598 // more than 1 argument specified - assume ( red, green, blue, alpha )
9599 if ( green !== undefined ) {
9600 red = [ red, green, blue, alpha ];
9604 if ( type === "string" ) {
9605 return this.parse( stringParse( red ) || colors._default );
9608 if ( type === "array" ) {
9609 each( spaces.rgba.props, function( key, prop ) {
9610 rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
9615 if ( type === "object" ) {
9616 if ( red instanceof color ) {
9617 each( spaces, function( spaceName, space ) {
9618 if ( red[ space.cache ] ) {
9619 inst[ space.cache ] = red[ space.cache ].slice();
9623 each( spaces, function( spaceName, space ) {
9624 var cache = space.cache;
9625 each( space.props, function( key, prop ) {
9627 // if the cache doesn't exist, and we know how to convert
9628 if ( !inst[ cache ] && space.to ) {
9630 // if the value was null, we don't need to copy it
9631 // if the key was alpha, we don't need to copy it either
9632 if ( key === "alpha" || red[ key ] == null ) {
9635 inst[ cache ] = space.to( inst._rgba );
9638 // this is the only case where we allow nulls for ALL properties.
9639 // call clamp with alwaysAllowEmpty
9640 inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
9643 // everything defined but alpha?
9644 if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
9645 // use the default of 1
9646 inst[ cache ][ 3 ] = 1;
9648 inst._rgba = space.from( inst[ cache ] );
9656 is: function( compare ) {
9657 var is = color( compare ),
9661 each( spaces, function( _, space ) {
9663 isCache = is[ space.cache ];
9665 localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
9666 each( space.props, function( _, prop ) {
9667 if ( isCache[ prop.idx ] != null ) {
9668 same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
9677 _space: function() {
9680 each( spaces, function( spaceName, space ) {
9681 if ( inst[ space.cache ] ) {
9682 used.push( spaceName );
9687 transition: function( other, distance ) {
9688 var end = color( other ),
9689 spaceName = end._space(),
9690 space = spaces[ spaceName ],
9691 startColor = this.alpha() === 0 ? color( "transparent" ) : this,
9692 start = startColor[ space.cache ] || space.to( startColor._rgba ),
9693 result = start.slice();
9695 end = end[ space.cache ];
9696 each( space.props, function( key, prop ) {
9697 var index = prop.idx,
9698 startValue = start[ index ],
9699 endValue = end[ index ],
9700 type = propTypes[ prop.type ] || {};
9702 // if null, don't override start value
9703 if ( endValue === null ) {
9706 // if null - use end
9707 if ( startValue === null ) {
9708 result[ index ] = endValue;
9711 if ( endValue - startValue > type.mod / 2 ) {
9712 startValue += type.mod;
9713 } else if ( startValue - endValue > type.mod / 2 ) {
9714 startValue -= type.mod;
9717 result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
9720 return this[ spaceName ]( result );
9722 blend: function( opaque ) {
9723 // if we are already opaque - return ourself
9724 if ( this._rgba[ 3 ] === 1 ) {
9728 var rgb = this._rgba.slice(),
9730 blend = color( opaque )._rgba;
9732 return color( jQuery.map( rgb, function( v, i ) {
9733 return ( 1 - a ) * blend[ i ] + a * v;
9736 toRgbaString: function() {
9737 var prefix = "rgba(",
9738 rgba = jQuery.map( this._rgba, function( v, i ) {
9739 return v == null ? ( i > 2 ? 1 : 0 ) : v;
9742 if ( rgba[ 3 ] === 1 ) {
9747 return prefix + rgba.join() + ")";
9749 toHslaString: function() {
9750 var prefix = "hsla(",
9751 hsla = jQuery.map( this.hsla(), function( v, i ) {
9758 v = Math.round( v * 100 ) + "%";
9763 if ( hsla[ 3 ] === 1 ) {
9767 return prefix + hsla.join() + ")";
9769 toHexString: function( includeAlpha ) {
9770 var rgba = this._rgba.slice(),
9773 if ( includeAlpha ) {
9774 rgba.push( ~~( alpha * 255 ) );
9777 return "#" + jQuery.map( rgba, function( v ) {
9779 // default to 0 when nulls exist
9780 v = ( v || 0 ).toString( 16 );
9781 return v.length === 1 ? "0" + v : v;
9784 toString: function() {
9785 return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
9788 color.fn.parse.prototype = color.fn;
9790 // hsla conversions adapted from:
9791 // https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
9793 function hue2rgb( p, q, h ) {
9796 return p + ( q - p ) * h * 6;
9802 return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6;
9807 spaces.hsla.to = function( rgba ) {
9808 if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
9809 return [ null, null, null, rgba[ 3 ] ];
9811 var r = rgba[ 0 ] / 255,
9812 g = rgba[ 1 ] / 255,
9813 b = rgba[ 2 ] / 255,
9815 max = Math.max( r, g, b ),
9816 min = Math.min( r, g, b ),
9822 if ( min === max ) {
9824 } else if ( r === max ) {
9825 h = ( 60 * ( g - b ) / diff ) + 360;
9826 } else if ( g === max ) {
9827 h = ( 60 * ( b - r ) / diff ) + 120;
9829 h = ( 60 * ( r - g ) / diff ) + 240;
9832 // chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
9833 // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
9836 } else if ( l <= 0.5 ) {
9839 s = diff / ( 2 - add );
9841 return [ Math.round(h) % 360, s, l, a == null ? 1 : a ];
9844 spaces.hsla.from = function( hsla ) {
9845 if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
9846 return [ null, null, null, hsla[ 3 ] ];
9848 var h = hsla[ 0 ] / 360,
9852 q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
9856 Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
9857 Math.round( hue2rgb( p, q, h ) * 255 ),
9858 Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
9863 each( spaces, function( spaceName, space ) {
9864 var props = space.props,
9865 cache = space.cache,
9869 // makes rgba() and hsla()
9870 color.fn[ spaceName ] = function( value ) {
9872 // generate a cache for this space if it doesn't exist
9873 if ( to && !this[ cache ] ) {
9874 this[ cache ] = to( this._rgba );
9876 if ( value === undefined ) {
9877 return this[ cache ].slice();
9881 type = jQuery.type( value ),
9882 arr = ( type === "array" || type === "object" ) ? value : arguments,
9883 local = this[ cache ].slice();
9885 each( props, function( key, prop ) {
9886 var val = arr[ type === "object" ? key : prop.idx ];
9887 if ( val == null ) {
9888 val = local[ prop.idx ];
9890 local[ prop.idx ] = clamp( val, prop );
9894 ret = color( from( local ) );
9895 ret[ cache ] = local;
9898 return color( local );
9902 // makes red() green() blue() alpha() hue() saturation() lightness()
9903 each( props, function( key, prop ) {
9904 // alpha is included in more than one space
9905 if ( color.fn[ key ] ) {
9908 color.fn[ key ] = function( value ) {
9909 var vtype = jQuery.type( value ),
9910 fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
9911 local = this[ fn ](),
9912 cur = local[ prop.idx ],
9915 if ( vtype === "undefined" ) {
9919 if ( vtype === "function" ) {
9920 value = value.call( this, cur );
9921 vtype = jQuery.type( value );
9923 if ( value == null && prop.empty ) {
9926 if ( vtype === "string" ) {
9927 match = rplusequals.exec( value );
9929 value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
9932 local[ prop.idx ] = value;
9933 return this[ fn ]( local );
9938 // add cssHook and .fx.step function for each named hook.
9939 // accept a space separated string of properties
9940 color.hook = function( hook ) {
9941 var hooks = hook.split( " " );
9942 each( hooks, function( i, hook ) {
9943 jQuery.cssHooks[ hook ] = {
9944 set: function( elem, value ) {
9945 var parsed, curElem,
9946 backgroundColor = "";
9948 if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) {
9949 value = color( parsed || value );
9950 if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
9951 curElem = hook === "backgroundColor" ? elem.parentNode : elem;
9953 (backgroundColor === "" || backgroundColor === "transparent") &&
9954 curElem && curElem.style
9957 backgroundColor = jQuery.css( curElem, "backgroundColor" );
9958 curElem = curElem.parentNode;
9963 value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
9968 value = value.toRgbaString();
9971 elem.style[ hook ] = value;
9973 // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit'
9977 jQuery.fx.step[ hook ] = function( fx ) {
9978 if ( !fx.colorInit ) {
9979 fx.start = color( fx.elem, hook );
9980 fx.end = color( fx.end );
9981 fx.colorInit = true;
9983 jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
9989 color.hook( stepHooks );
9991 jQuery.cssHooks.borderColor = {
9992 expand: function( value ) {
9995 each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
9996 expanded[ "border" + part + "Color" ] = value;
10002 // Basic color names only.
10003 // Usage of any of the other color names requires adding yourself or including
10004 // jquery.color.svg-names.js.
10005 colors = jQuery.Color.names = {
10006 // 4.1. Basic color keywords
10010 fuchsia: "#ff00ff",
10024 // 4.2.3. "transparent" color keyword
10025 transparent: [ null, null, null, 0 ],
10027 _default: "#ffffff"
10032 /******************************************************************************/
10033 /****************************** CLASS ANIMATIONS ******************************/
10034 /******************************************************************************/
10037 var classAnimationActions = [ "add", "remove", "toggle" ],
10038 shorthandStyles = {
10050 $.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) {
10051 $.fx.step[ prop ] = function( fx ) {
10052 if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
10053 jQuery.style( fx.elem, prop, fx.end );
10059 function getElementStyles( elem ) {
10061 style = elem.ownerDocument.defaultView ?
10062 elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :
10066 if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
10067 len = style.length;
10069 key = style[ len ];
10070 if ( typeof style[ key ] === "string" ) {
10071 styles[ $.camelCase( key ) ] = style[ key ];
10074 // support: Opera, IE <9
10076 for ( key in style ) {
10077 if ( typeof style[ key ] === "string" ) {
10078 styles[ key ] = style[ key ];
10086 function styleDifference( oldStyle, newStyle ) {
10090 for ( name in newStyle ) {
10091 value = newStyle[ name ];
10092 if ( oldStyle[ name ] !== value ) {
10093 if ( !shorthandStyles[ name ] ) {
10094 if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
10095 diff[ name ] = value;
10104 // support: jQuery <1.8
10105 if ( !$.fn.addBack ) {
10106 $.fn.addBack = function( selector ) {
10107 return this.add( selector == null ?
10108 this.prevObject : this.prevObject.filter( selector )
10113 $.effects.animateClass = function( value, duration, easing, callback ) {
10114 var o = $.speed( duration, easing, callback );
10116 return this.queue( function() {
10117 var animated = $( this ),
10118 baseClass = animated.attr( "class" ) || "",
10120 allAnimations = o.children ? animated.find( "*" ).addBack() : animated;
10122 // map the animated objects to store the original styles.
10123 allAnimations = allAnimations.map(function() {
10124 var el = $( this );
10127 start: getElementStyles( this )
10131 // apply class change
10132 applyClassChange = function() {
10133 $.each( classAnimationActions, function(i, action) {
10134 if ( value[ action ] ) {
10135 animated[ action + "Class" ]( value[ action ] );
10139 applyClassChange();
10141 // map all animated objects again - calculate new styles and diff
10142 allAnimations = allAnimations.map(function() {
10143 this.end = getElementStyles( this.el[ 0 ] );
10144 this.diff = styleDifference( this.start, this.end );
10148 // apply original class
10149 animated.attr( "class", baseClass );
10151 // map all animated objects again - this time collecting a promise
10152 allAnimations = allAnimations.map(function() {
10153 var styleInfo = this,
10154 dfd = $.Deferred(),
10155 opts = $.extend({}, o, {
10157 complete: function() {
10158 dfd.resolve( styleInfo );
10162 this.el.animate( this.diff, opts );
10163 return dfd.promise();
10166 // once all animations have completed:
10167 $.when.apply( $, allAnimations.get() ).done(function() {
10169 // set the final class
10170 applyClassChange();
10172 // for each animated element,
10173 // clear all css properties that were animated
10174 $.each( arguments, function() {
10176 $.each( this.diff, function(key) {
10181 // this is guarnteed to be there if you use jQuery.speed()
10182 // it also handles dequeuing the next anim...
10183 o.complete.call( animated[ 0 ] );
10189 addClass: (function( orig ) {
10190 return function( classNames, speed, easing, callback ) {
10192 $.effects.animateClass.call( this,
10193 { add: classNames }, speed, easing, callback ) :
10194 orig.apply( this, arguments );
10196 })( $.fn.addClass ),
10198 removeClass: (function( orig ) {
10199 return function( classNames, speed, easing, callback ) {
10200 return arguments.length > 1 ?
10201 $.effects.animateClass.call( this,
10202 { remove: classNames }, speed, easing, callback ) :
10203 orig.apply( this, arguments );
10205 })( $.fn.removeClass ),
10207 toggleClass: (function( orig ) {
10208 return function( classNames, force, speed, easing, callback ) {
10209 if ( typeof force === "boolean" || force === undefined ) {
10211 // without speed parameter
10212 return orig.apply( this, arguments );
10214 return $.effects.animateClass.call( this,
10215 (force ? { add: classNames } : { remove: classNames }),
10216 speed, easing, callback );
10219 // without force parameter
10220 return $.effects.animateClass.call( this,
10221 { toggle: classNames }, force, speed, easing );
10224 })( $.fn.toggleClass ),
10226 switchClass: function( remove, add, speed, easing, callback) {
10227 return $.effects.animateClass.call( this, {
10230 }, speed, easing, callback );
10236 /******************************************************************************/
10237 /*********************************** EFFECTS **********************************/
10238 /******************************************************************************/
10242 $.extend( $.effects, {
10245 // Saves a set of properties in a data storage
10246 save: function( element, set ) {
10247 for ( var i = 0; i < set.length; i++ ) {
10248 if ( set[ i ] !== null ) {
10249 element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
10254 // Restores a set of previously saved properties from a data storage
10255 restore: function( element, set ) {
10257 for ( i = 0; i < set.length; i++ ) {
10258 if ( set[ i ] !== null ) {
10259 val = element.data( dataSpace + set[ i ] );
10260 // support: jQuery 1.6.2
10261 // http://bugs.jquery.com/ticket/9917
10262 // jQuery 1.6.2 incorrectly returns undefined for any falsy value.
10263 // We can't differentiate between "" and 0 here, so we just assume
10264 // empty string since it's likely to be a more common value...
10265 if ( val === undefined ) {
10268 element.css( set[ i ], val );
10273 setMode: function( el, mode ) {
10274 if (mode === "toggle") {
10275 mode = el.is( ":hidden" ) ? "show" : "hide";
10280 // Translates a [top,left] array into a baseline value
10281 // this should be a little more flexible in the future to handle a string & hash
10282 getBaseline: function( origin, original ) {
10284 switch ( origin[ 0 ] ) {
10285 case "top": y = 0; break;
10286 case "middle": y = 0.5; break;
10287 case "bottom": y = 1; break;
10288 default: y = origin[ 0 ] / original.height;
10290 switch ( origin[ 1 ] ) {
10291 case "left": x = 0; break;
10292 case "center": x = 0.5; break;
10293 case "right": x = 1; break;
10294 default: x = origin[ 1 ] / original.width;
10302 // Wraps the element around a wrapper that copies position properties
10303 createWrapper: function( element ) {
10305 // if the element is already wrapped, return it
10306 if ( element.parent().is( ".ui-effects-wrapper" )) {
10307 return element.parent();
10310 // wrap the element
10312 width: element.outerWidth(true),
10313 height: element.outerHeight(true),
10314 "float": element.css( "float" )
10316 wrapper = $( "<div></div>" )
10317 .addClass( "ui-effects-wrapper" )
10320 background: "transparent",
10325 // Store the size in case width/height are defined in % - Fixes #5245
10327 width: element.width(),
10328 height: element.height()
10330 active = document.activeElement;
10332 // support: Firefox
10333 // Firefox incorrectly exposes anonymous content
10334 // https://bugzilla.mozilla.org/show_bug.cgi?id=561664
10338 active = document.body;
10341 element.wrap( wrapper );
10343 // Fixes #7595 - Elements lose focus when wrapped.
10344 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
10345 $( active ).focus();
10348 wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element
10350 // transfer positioning properties to the wrapper
10351 if ( element.css( "position" ) === "static" ) {
10352 wrapper.css({ position: "relative" });
10353 element.css({ position: "relative" });
10356 position: element.css( "position" ),
10357 zIndex: element.css( "z-index" )
10359 $.each([ "top", "left", "bottom", "right" ], function(i, pos) {
10360 props[ pos ] = element.css( pos );
10361 if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
10362 props[ pos ] = "auto";
10366 position: "relative",
10375 return wrapper.css( props ).show();
10378 removeWrapper: function( element ) {
10379 var active = document.activeElement;
10381 if ( element.parent().is( ".ui-effects-wrapper" ) ) {
10382 element.parent().replaceWith( element );
10384 // Fixes #7595 - Elements lose focus when wrapped.
10385 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
10386 $( active ).focus();
10393 setTransition: function( element, list, factor, value ) {
10394 value = value || {};
10395 $.each( list, function( i, x ) {
10396 var unit = element.cssUnit( x );
10397 if ( unit[ 0 ] > 0 ) {
10398 value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
10405 // return an effect options object for the given parameters:
10406 function _normalizeArguments( effect, options, speed, callback ) {
10408 // allow passing all options as the first parameter
10409 if ( $.isPlainObject( effect ) ) {
10411 effect = effect.effect;
10414 // convert to an object
10415 effect = { effect: effect };
10417 // catch (effect, null, ...)
10418 if ( options == null ) {
10422 // catch (effect, callback)
10423 if ( $.isFunction( options ) ) {
10424 callback = options;
10429 // catch (effect, speed, ?)
10430 if ( typeof options === "number" || $.fx.speeds[ options ] ) {
10436 // catch (effect, options, callback)
10437 if ( $.isFunction( speed ) ) {
10442 // add options to effect
10444 $.extend( effect, options );
10447 speed = speed || options.duration;
10448 effect.duration = $.fx.off ? 0 :
10449 typeof speed === "number" ? speed :
10450 speed in $.fx.speeds ? $.fx.speeds[ speed ] :
10451 $.fx.speeds._default;
10453 effect.complete = callback || options.complete;
10458 function standardAnimationOption( option ) {
10459 // Valid standard speeds (nothing, number, named speed)
10460 if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) {
10464 // Invalid strings - treat as "normal" speed
10465 if ( typeof option === "string" && !$.effects.effect[ option ] ) {
10469 // Complete callback
10470 if ( $.isFunction( option ) ) {
10474 // Options hash (but not naming an effect)
10475 if ( typeof option === "object" && !option.effect ) {
10479 // Didn't match any standard API
10484 effect: function( /* effect, options, speed, callback */ ) {
10485 var args = _normalizeArguments.apply( this, arguments ),
10487 queue = args.queue,
10488 effectMethod = $.effects.effect[ args.effect ];
10490 if ( $.fx.off || !effectMethod ) {
10491 // delegate to the original method (e.g., .show()) if possible
10493 return this[ mode ]( args.duration, args.complete );
10495 return this.each( function() {
10496 if ( args.complete ) {
10497 args.complete.call( this );
10503 function run( next ) {
10504 var elem = $( this ),
10505 complete = args.complete,
10509 if ( $.isFunction( complete ) ) {
10510 complete.call( elem[0] );
10512 if ( $.isFunction( next ) ) {
10517 // If the element already has the correct final state, delegate to
10518 // the core methods so the internal tracking of "olddisplay" works.
10519 if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
10523 effectMethod.call( elem[0], args, done );
10527 return queue === false ? this.each( run ) : this.queue( queue || "fx", run );
10530 show: (function( orig ) {
10531 return function( option ) {
10532 if ( standardAnimationOption( option ) ) {
10533 return orig.apply( this, arguments );
10535 var args = _normalizeArguments.apply( this, arguments );
10536 args.mode = "show";
10537 return this.effect.call( this, args );
10542 hide: (function( orig ) {
10543 return function( option ) {
10544 if ( standardAnimationOption( option ) ) {
10545 return orig.apply( this, arguments );
10547 var args = _normalizeArguments.apply( this, arguments );
10548 args.mode = "hide";
10549 return this.effect.call( this, args );
10554 toggle: (function( orig ) {
10555 return function( option ) {
10556 if ( standardAnimationOption( option ) || typeof option === "boolean" ) {
10557 return orig.apply( this, arguments );
10559 var args = _normalizeArguments.apply( this, arguments );
10560 args.mode = "toggle";
10561 return this.effect.call( this, args );
10566 // helper functions
10567 cssUnit: function(key) {
10568 var style = this.css( key ),
10571 $.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
10572 if ( style.indexOf( unit ) > 0 ) {
10573 val = [ parseFloat( style ), unit ];
10582 /******************************************************************************/
10583 /*********************************** EASING ***********************************/
10584 /******************************************************************************/
10588 // based on easing equations from Robert Penner (http://www.robertpenner.com/easing)
10590 var baseEasings = {};
10592 $.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
10593 baseEasings[ name ] = function( p ) {
10594 return Math.pow( p, i + 2 );
10598 $.extend( baseEasings, {
10599 Sine: function( p ) {
10600 return 1 - Math.cos( p * Math.PI / 2 );
10602 Circ: function( p ) {
10603 return 1 - Math.sqrt( 1 - p * p );
10605 Elastic: function( p ) {
10606 return p === 0 || p === 1 ? p :
10607 -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 );
10609 Back: function( p ) {
10610 return p * p * ( 3 * p - 2 );
10612 Bounce: function( p ) {
10616 while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
10617 return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
10621 $.each( baseEasings, function( name, easeIn ) {
10622 $.easing[ "easeIn" + name ] = easeIn;
10623 $.easing[ "easeOut" + name ] = function( p ) {
10624 return 1 - easeIn( 1 - p );
10626 $.easing[ "easeInOut" + name ] = function( p ) {
10628 easeIn( p * 2 ) / 2 :
10629 1 - easeIn( p * -2 + 2 ) / 2;
10635 var effect = $.effects;
10639 * jQuery UI Effects Blind 1.11.4
10640 * http://jqueryui.com
10642 * Copyright jQuery Foundation and other contributors
10643 * Released under the MIT license.
10644 * http://jquery.org/license
10646 * http://api.jqueryui.com/blind-effect/
10650 var effectBlind = $.effects.effect.blind = function( o, done ) {
10652 var el = $( this ),
10653 rvertical = /up|down|vertical/,
10654 rpositivemotion = /up|left|vertical|horizontal/,
10655 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
10656 mode = $.effects.setMode( el, o.mode || "hide" ),
10657 direction = o.direction || "up",
10658 vertical = rvertical.test( direction ),
10659 ref = vertical ? "height" : "width",
10660 ref2 = vertical ? "top" : "left",
10661 motion = rpositivemotion.test( direction ),
10663 show = mode === "show",
10664 wrapper, distance, margin;
10666 // if already wrapped, the wrapper's properties are my property. #6245
10667 if ( el.parent().is( ".ui-effects-wrapper" ) ) {
10668 $.effects.save( el.parent(), props );
10670 $.effects.save( el, props );
10673 wrapper = $.effects.createWrapper( el ).css({
10677 distance = wrapper[ ref ]();
10678 margin = parseFloat( wrapper.css( ref2 ) ) || 0;
10680 animation[ ref ] = show ? distance : 0;
10683 .css( vertical ? "bottom" : "right", 0 )
10684 .css( vertical ? "top" : "left", "auto" )
10685 .css({ position: "absolute" });
10687 animation[ ref2 ] = show ? margin : distance + margin;
10690 // start at 0 if we are showing
10692 wrapper.css( ref, 0 );
10694 wrapper.css( ref2, margin + distance );
10699 wrapper.animate( animation, {
10700 duration: o.duration,
10703 complete: function() {
10704 if ( mode === "hide" ) {
10707 $.effects.restore( el, props );
10708 $.effects.removeWrapper( el );
10716 * jQuery UI Effects Bounce 1.11.4
10717 * http://jqueryui.com
10719 * Copyright jQuery Foundation and other contributors
10720 * Released under the MIT license.
10721 * http://jquery.org/license
10723 * http://api.jqueryui.com/bounce-effect/
10727 var effectBounce = $.effects.effect.bounce = function( o, done ) {
10728 var el = $( this ),
10729 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
10732 mode = $.effects.setMode( el, o.mode || "effect" ),
10733 hide = mode === "hide",
10734 show = mode === "show",
10735 direction = o.direction || "up",
10736 distance = o.distance,
10737 times = o.times || 5,
10739 // number of internal animations
10740 anims = times * 2 + ( show || hide ? 1 : 0 ),
10741 speed = o.duration / anims,
10745 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
10746 motion = ( direction === "up" || direction === "left" ),
10751 // we will need to re-assemble the queue to stack our animations in place
10752 queue = el.queue(),
10753 queuelen = queue.length;
10755 // Avoid touching opacity to prevent clearType and PNG issues in IE
10756 if ( show || hide ) {
10757 props.push( "opacity" );
10760 $.effects.save( el, props );
10762 $.effects.createWrapper( el ); // Create Wrapper
10764 // default distance for the BIGGEST bounce is the outer Distance / 3
10766 distance = el[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
10770 downAnim = { opacity: 1 };
10771 downAnim[ ref ] = 0;
10773 // if we are showing, force opacity 0 and set the initial position
10774 // then do the "first" animation
10775 el.css( "opacity", 0 )
10776 .css( ref, motion ? -distance * 2 : distance * 2 )
10777 .animate( downAnim, speed, easing );
10780 // start at the smallest distance if we are hiding
10782 distance = distance / Math.pow( 2, times - 1 );
10786 downAnim[ ref ] = 0;
10787 // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
10788 for ( i = 0; i < times; i++ ) {
10790 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
10792 el.animate( upAnim, speed, easing )
10793 .animate( downAnim, speed, easing );
10795 distance = hide ? distance * 2 : distance / 2;
10798 // Last Bounce when Hiding
10800 upAnim = { opacity: 0 };
10801 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
10803 el.animate( upAnim, speed, easing );
10806 el.queue(function() {
10810 $.effects.restore( el, props );
10811 $.effects.removeWrapper( el );
10815 // inject all the animations we just queued to be first in line (after "inprogress")
10816 if ( queuelen > 1) {
10817 queue.splice.apply( queue,
10818 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
10826 * jQuery UI Effects Clip 1.11.4
10827 * http://jqueryui.com
10829 * Copyright jQuery Foundation and other contributors
10830 * Released under the MIT license.
10831 * http://jquery.org/license
10833 * http://api.jqueryui.com/clip-effect/
10837 var effectClip = $.effects.effect.clip = function( o, done ) {
10839 var el = $( this ),
10840 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
10841 mode = $.effects.setMode( el, o.mode || "hide" ),
10842 show = mode === "show",
10843 direction = o.direction || "vertical",
10844 vert = direction === "vertical",
10845 size = vert ? "height" : "width",
10846 position = vert ? "top" : "left",
10848 wrapper, animate, distance;
10851 $.effects.save( el, props );
10855 wrapper = $.effects.createWrapper( el ).css({
10858 animate = ( el[0].tagName === "IMG" ) ? wrapper : el;
10859 distance = animate[ size ]();
10863 animate.css( size, 0 );
10864 animate.css( position, distance / 2 );
10867 // Create Animation Object:
10868 animation[ size ] = show ? distance : 0;
10869 animation[ position ] = show ? 0 : distance / 2;
10872 animate.animate( animation, {
10874 duration: o.duration,
10876 complete: function() {
10880 $.effects.restore( el, props );
10881 $.effects.removeWrapper( el );
10890 * jQuery UI Effects Drop 1.11.4
10891 * http://jqueryui.com
10893 * Copyright jQuery Foundation and other contributors
10894 * Released under the MIT license.
10895 * http://jquery.org/license
10897 * http://api.jqueryui.com/drop-effect/
10901 var effectDrop = $.effects.effect.drop = function( o, done ) {
10903 var el = $( this ),
10904 props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ],
10905 mode = $.effects.setMode( el, o.mode || "hide" ),
10906 show = mode === "show",
10907 direction = o.direction || "left",
10908 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
10909 motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg",
10911 opacity: show ? 1 : 0
10916 $.effects.save( el, props );
10918 $.effects.createWrapper( el );
10920 distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ) / 2;
10924 .css( "opacity", 0 )
10925 .css( ref, motion === "pos" ? -distance : distance );
10929 animation[ ref ] = ( show ?
10930 ( motion === "pos" ? "+=" : "-=" ) :
10931 ( motion === "pos" ? "-=" : "+=" ) ) +
10935 el.animate( animation, {
10937 duration: o.duration,
10939 complete: function() {
10940 if ( mode === "hide" ) {
10943 $.effects.restore( el, props );
10944 $.effects.removeWrapper( el );
10952 * jQuery UI Effects Explode 1.11.4
10953 * http://jqueryui.com
10955 * Copyright jQuery Foundation and other contributors
10956 * Released under the MIT license.
10957 * http://jquery.org/license
10959 * http://api.jqueryui.com/explode-effect/
10963 var effectExplode = $.effects.effect.explode = function( o, done ) {
10965 var rows = o.pieces ? Math.round( Math.sqrt( o.pieces ) ) : 3,
10968 mode = $.effects.setMode( el, o.mode || "hide" ),
10969 show = mode === "show",
10971 // show and then visibility:hidden the element before calculating offset
10972 offset = el.show().css( "visibility", "hidden" ).offset(),
10974 // width and height of a piece
10975 width = Math.ceil( el.outerWidth() / cells ),
10976 height = Math.ceil( el.outerHeight() / rows ),
10980 i, j, left, top, mx, my;
10982 // children animate complete:
10983 function childComplete() {
10984 pieces.push( this );
10985 if ( pieces.length === rows * cells ) {
10990 // clone the element for each row and cell.
10991 for ( i = 0; i < rows ; i++ ) { // ===>
10992 top = offset.top + i * height;
10993 my = i - ( rows - 1 ) / 2 ;
10995 for ( j = 0; j < cells ; j++ ) { // |||
10996 left = offset.left + j * width;
10997 mx = j - ( cells - 1 ) / 2 ;
10999 // Create a clone of the now hidden main element that will be absolute positioned
11000 // within a wrapper div off the -left and -top equal to size of our pieces
11003 .appendTo( "body" )
11004 .wrap( "<div></div>" )
11006 position: "absolute",
11007 visibility: "visible",
11012 // select the wrapper - make it overflow: hidden and absolute positioned based on
11013 // where the original was located +left and +top equal to the size of pieces
11015 .addClass( "ui-effects-explode" )
11017 position: "absolute",
11018 overflow: "hidden",
11021 left: left + ( show ? mx * width : 0 ),
11022 top: top + ( show ? my * height : 0 ),
11023 opacity: show ? 0 : 1
11025 left: left + ( show ? 0 : mx * width ),
11026 top: top + ( show ? 0 : my * height ),
11027 opacity: show ? 1 : 0
11028 }, o.duration || 500, o.easing, childComplete );
11032 function animComplete() {
11034 visibility: "visible"
11036 $( pieces ).remove();
11046 * jQuery UI Effects Fade 1.11.4
11047 * http://jqueryui.com
11049 * Copyright jQuery Foundation and other contributors
11050 * Released under the MIT license.
11051 * http://jquery.org/license
11053 * http://api.jqueryui.com/fade-effect/
11057 var effectFade = $.effects.effect.fade = function( o, done ) {
11058 var el = $( this ),
11059 mode = $.effects.setMode( el, o.mode || "toggle" );
11065 duration: o.duration,
11073 * jQuery UI Effects Fold 1.11.4
11074 * http://jqueryui.com
11076 * Copyright jQuery Foundation and other contributors
11077 * Released under the MIT license.
11078 * http://jquery.org/license
11080 * http://api.jqueryui.com/fold-effect/
11084 var effectFold = $.effects.effect.fold = function( o, done ) {
11087 var el = $( this ),
11088 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
11089 mode = $.effects.setMode( el, o.mode || "hide" ),
11090 show = mode === "show",
11091 hide = mode === "hide",
11092 size = o.size || 15,
11093 percent = /([0-9]+)%/.exec( size ),
11094 horizFirst = !!o.horizFirst,
11095 widthFirst = show !== horizFirst,
11096 ref = widthFirst ? [ "width", "height" ] : [ "height", "width" ],
11097 duration = o.duration / 2,
11102 $.effects.save( el, props );
11106 wrapper = $.effects.createWrapper( el ).css({
11109 distance = widthFirst ?
11110 [ wrapper.width(), wrapper.height() ] :
11111 [ wrapper.height(), wrapper.width() ];
11114 size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
11117 wrapper.css( horizFirst ? {
11127 animation1[ ref[ 0 ] ] = show ? distance[ 0 ] : size;
11128 animation2[ ref[ 1 ] ] = show ? distance[ 1 ] : 0;
11132 .animate( animation1, duration, o.easing )
11133 .animate( animation2, duration, o.easing, function() {
11137 $.effects.restore( el, props );
11138 $.effects.removeWrapper( el );
11146 * jQuery UI Effects Highlight 1.11.4
11147 * http://jqueryui.com
11149 * Copyright jQuery Foundation and other contributors
11150 * Released under the MIT license.
11151 * http://jquery.org/license
11153 * http://api.jqueryui.com/highlight-effect/
11157 var effectHighlight = $.effects.effect.highlight = function( o, done ) {
11158 var elem = $( this ),
11159 props = [ "backgroundImage", "backgroundColor", "opacity" ],
11160 mode = $.effects.setMode( elem, o.mode || "show" ),
11162 backgroundColor: elem.css( "backgroundColor" )
11165 if (mode === "hide") {
11166 animation.opacity = 0;
11169 $.effects.save( elem, props );
11174 backgroundImage: "none",
11175 backgroundColor: o.color || "#ffff99"
11177 .animate( animation, {
11179 duration: o.duration,
11181 complete: function() {
11182 if ( mode === "hide" ) {
11185 $.effects.restore( elem, props );
11193 * jQuery UI Effects Size 1.11.4
11194 * http://jqueryui.com
11196 * Copyright jQuery Foundation and other contributors
11197 * Released under the MIT license.
11198 * http://jquery.org/license
11200 * http://api.jqueryui.com/size-effect/
11204 var effectSize = $.effects.effect.size = function( o, done ) {
11207 var original, baseline, factor,
11209 props0 = [ "position", "top", "bottom", "left", "right", "width", "height", "overflow", "opacity" ],
11212 props1 = [ "position", "top", "bottom", "left", "right", "overflow", "opacity" ],
11214 // Copy for children
11215 props2 = [ "width", "height", "overflow" ],
11216 cProps = [ "fontSize" ],
11217 vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
11218 hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],
11221 mode = $.effects.setMode( el, o.mode || "effect" ),
11222 restore = o.restore || mode !== "effect",
11223 scale = o.scale || "both",
11224 origin = o.origin || [ "middle", "center" ],
11225 position = el.css( "position" ),
11226 props = restore ? props0 : props1,
11234 if ( mode === "show" ) {
11238 height: el.height(),
11240 outerHeight: el.outerHeight(),
11241 outerWidth: el.outerWidth()
11244 if ( o.mode === "toggle" && mode === "show" ) {
11245 el.from = o.to || zero;
11246 el.to = o.from || original;
11248 el.from = o.from || ( mode === "show" ? zero : original );
11249 el.to = o.to || ( mode === "hide" ? zero : original );
11252 // Set scaling factor
11255 y: el.from.height / original.height,
11256 x: el.from.width / original.width
11259 y: el.to.height / original.height,
11260 x: el.to.width / original.width
11264 // Scale the css box
11265 if ( scale === "box" || scale === "both" ) {
11267 // Vertical props scaling
11268 if ( factor.from.y !== factor.to.y ) {
11269 props = props.concat( vProps );
11270 el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from );
11271 el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to );
11274 // Horizontal props scaling
11275 if ( factor.from.x !== factor.to.x ) {
11276 props = props.concat( hProps );
11277 el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from );
11278 el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to );
11282 // Scale the content
11283 if ( scale === "content" || scale === "both" ) {
11285 // Vertical props scaling
11286 if ( factor.from.y !== factor.to.y ) {
11287 props = props.concat( cProps ).concat( props2 );
11288 el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from );
11289 el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to );
11293 $.effects.save( el, props );
11295 $.effects.createWrapper( el );
11296 el.css( "overflow", "hidden" ).css( el.from );
11299 if (origin) { // Calculate baseline shifts
11300 baseline = $.effects.getBaseline( origin, original );
11301 el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y;
11302 el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x;
11303 el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y;
11304 el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x;
11306 el.css( el.from ); // set top & left
11309 if ( scale === "content" || scale === "both" ) { // Scale the children
11311 // Add margins/font-size
11312 vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat(cProps);
11313 hProps = hProps.concat([ "marginLeft", "marginRight" ]);
11314 props2 = props0.concat(vProps).concat(hProps);
11316 el.find( "*[width]" ).each( function() {
11317 var child = $( this ),
11319 height: child.height(),
11320 width: child.width(),
11321 outerHeight: child.outerHeight(),
11322 outerWidth: child.outerWidth()
11325 $.effects.save(child, props2);
11329 height: c_original.height * factor.from.y,
11330 width: c_original.width * factor.from.x,
11331 outerHeight: c_original.outerHeight * factor.from.y,
11332 outerWidth: c_original.outerWidth * factor.from.x
11335 height: c_original.height * factor.to.y,
11336 width: c_original.width * factor.to.x,
11337 outerHeight: c_original.height * factor.to.y,
11338 outerWidth: c_original.width * factor.to.x
11341 // Vertical props scaling
11342 if ( factor.from.y !== factor.to.y ) {
11343 child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from );
11344 child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to );
11347 // Horizontal props scaling
11348 if ( factor.from.x !== factor.to.x ) {
11349 child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from );
11350 child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to );
11353 // Animate children
11354 child.css( child.from );
11355 child.animate( child.to, o.duration, o.easing, function() {
11357 // Restore children
11359 $.effects.restore( child, props2 );
11366 el.animate( el.to, {
11368 duration: o.duration,
11370 complete: function() {
11371 if ( el.to.opacity === 0 ) {
11372 el.css( "opacity", el.from.opacity );
11374 if ( mode === "hide" ) {
11377 $.effects.restore( el, props );
11380 // we need to calculate our new positioning based on the scaling
11381 if ( position === "static" ) {
11383 position: "relative",
11388 $.each([ "top", "left" ], function( idx, pos ) {
11389 el.css( pos, function( _, str ) {
11390 var val = parseInt( str, 10 ),
11391 toRef = idx ? el.to.left : el.to.top;
11393 // if original was "auto", recalculate the new value from wrapper
11394 if ( str === "auto" ) {
11395 return toRef + "px";
11398 return val + toRef + "px";
11404 $.effects.removeWrapper( el );
11413 * jQuery UI Effects Scale 1.11.4
11414 * http://jqueryui.com
11416 * Copyright jQuery Foundation and other contributors
11417 * Released under the MIT license.
11418 * http://jquery.org/license
11420 * http://api.jqueryui.com/scale-effect/
11424 var effectScale = $.effects.effect.scale = function( o, done ) {
11427 var el = $( this ),
11428 options = $.extend( true, {}, o ),
11429 mode = $.effects.setMode( el, o.mode || "effect" ),
11430 percent = parseInt( o.percent, 10 ) ||
11431 ( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === "hide" ? 0 : 100 ) ),
11432 direction = o.direction || "both",
11435 height: el.height(),
11437 outerHeight: el.outerHeight(),
11438 outerWidth: el.outerWidth()
11441 y: direction !== "horizontal" ? (percent / 100) : 1,
11442 x: direction !== "vertical" ? (percent / 100) : 1
11445 // We are going to pass this effect to the size effect:
11446 options.effect = "size";
11447 options.queue = false;
11448 options.complete = done;
11450 // Set default origin and restore for show/hide
11451 if ( mode !== "effect" ) {
11452 options.origin = origin || [ "middle", "center" ];
11453 options.restore = true;
11456 options.from = o.from || ( mode === "show" ? {
11463 height: original.height * factor.y,
11464 width: original.width * factor.x,
11465 outerHeight: original.outerHeight * factor.y,
11466 outerWidth: original.outerWidth * factor.x
11469 // Fade option to support puff
11470 if ( options.fade ) {
11471 if ( mode === "show" ) {
11472 options.from.opacity = 0;
11473 options.to.opacity = 1;
11475 if ( mode === "hide" ) {
11476 options.from.opacity = 1;
11477 options.to.opacity = 0;
11482 el.effect( options );
11488 * jQuery UI Effects Puff 1.11.4
11489 * http://jqueryui.com
11491 * Copyright jQuery Foundation and other contributors
11492 * Released under the MIT license.
11493 * http://jquery.org/license
11495 * http://api.jqueryui.com/puff-effect/
11499 var effectPuff = $.effects.effect.puff = function( o, done ) {
11500 var elem = $( this ),
11501 mode = $.effects.setMode( elem, o.mode || "hide" ),
11502 hide = mode === "hide",
11503 percent = parseInt( o.percent, 10 ) || 150,
11504 factor = percent / 100,
11506 height: elem.height(),
11507 width: elem.width(),
11508 outerHeight: elem.outerHeight(),
11509 outerWidth: elem.outerWidth()
11518 percent: hide ? percent : 100,
11522 height: original.height * factor,
11523 width: original.width * factor,
11524 outerHeight: original.outerHeight * factor,
11525 outerWidth: original.outerWidth * factor
11534 * jQuery UI Effects Pulsate 1.11.4
11535 * http://jqueryui.com
11537 * Copyright jQuery Foundation and other contributors
11538 * Released under the MIT license.
11539 * http://jquery.org/license
11541 * http://api.jqueryui.com/pulsate-effect/
11545 var effectPulsate = $.effects.effect.pulsate = function( o, done ) {
11546 var elem = $( this ),
11547 mode = $.effects.setMode( elem, o.mode || "show" ),
11548 show = mode === "show",
11549 hide = mode === "hide",
11550 showhide = ( show || mode === "hide" ),
11552 // showing or hiding leaves of the "last" animation
11553 anims = ( ( o.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
11554 duration = o.duration / anims,
11556 queue = elem.queue(),
11557 queuelen = queue.length,
11560 if ( show || !elem.is(":visible")) {
11561 elem.css( "opacity", 0 ).show();
11565 // anims - 1 opacity "toggles"
11566 for ( i = 1; i < anims; i++ ) {
11569 }, duration, o.easing );
11570 animateTo = 1 - animateTo;
11575 }, duration, o.easing);
11577 elem.queue(function() {
11584 // We just queued up "anims" animations, we need to put them next in the queue
11585 if ( queuelen > 1 ) {
11586 queue.splice.apply( queue,
11587 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
11594 * jQuery UI Effects Shake 1.11.4
11595 * http://jqueryui.com
11597 * Copyright jQuery Foundation and other contributors
11598 * Released under the MIT license.
11599 * http://jquery.org/license
11601 * http://api.jqueryui.com/shake-effect/
11605 var effectShake = $.effects.effect.shake = function( o, done ) {
11607 var el = $( this ),
11608 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
11609 mode = $.effects.setMode( el, o.mode || "effect" ),
11610 direction = o.direction || "left",
11611 distance = o.distance || 20,
11612 times = o.times || 3,
11613 anims = times * 2 + 1,
11614 speed = Math.round( o.duration / anims ),
11615 ref = (direction === "up" || direction === "down") ? "top" : "left",
11616 positiveMotion = (direction === "up" || direction === "left"),
11622 // we will need to re-assemble the queue to stack our animations in place
11623 queue = el.queue(),
11624 queuelen = queue.length;
11626 $.effects.save( el, props );
11628 $.effects.createWrapper( el );
11631 animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
11632 animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
11633 animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;
11636 el.animate( animation, speed, o.easing );
11639 for ( i = 1; i < times; i++ ) {
11640 el.animate( animation1, speed, o.easing ).animate( animation2, speed, o.easing );
11643 .animate( animation1, speed, o.easing )
11644 .animate( animation, speed / 2, o.easing )
11645 .queue(function() {
11646 if ( mode === "hide" ) {
11649 $.effects.restore( el, props );
11650 $.effects.removeWrapper( el );
11654 // inject all the animations we just queued to be first in line (after "inprogress")
11655 if ( queuelen > 1) {
11656 queue.splice.apply( queue,
11657 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
11665 * jQuery UI Effects Slide 1.11.4
11666 * http://jqueryui.com
11668 * Copyright jQuery Foundation and other contributors
11669 * Released under the MIT license.
11670 * http://jquery.org/license
11672 * http://api.jqueryui.com/slide-effect/
11676 var effectSlide = $.effects.effect.slide = function( o, done ) {
11679 var el = $( this ),
11680 props = [ "position", "top", "bottom", "left", "right", "width", "height" ],
11681 mode = $.effects.setMode( el, o.mode || "show" ),
11682 show = mode === "show",
11683 direction = o.direction || "left",
11684 ref = (direction === "up" || direction === "down") ? "top" : "left",
11685 positiveMotion = (direction === "up" || direction === "left"),
11690 $.effects.save( el, props );
11692 distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true );
11694 $.effects.createWrapper( el ).css({
11699 el.css( ref, positiveMotion ? (isNaN(distance) ? "-" + distance : -distance) : distance );
11703 animation[ ref ] = ( show ?
11704 ( positiveMotion ? "+=" : "-=") :
11705 ( positiveMotion ? "-=" : "+=")) +
11709 el.animate( animation, {
11711 duration: o.duration,
11713 complete: function() {
11714 if ( mode === "hide" ) {
11717 $.effects.restore( el, props );
11718 $.effects.removeWrapper( el );
11726 * jQuery UI Effects Transfer 1.11.4
11727 * http://jqueryui.com
11729 * Copyright jQuery Foundation and other contributors
11730 * Released under the MIT license.
11731 * http://jquery.org/license
11733 * http://api.jqueryui.com/transfer-effect/
11737 var effectTransfer = $.effects.effect.transfer = function( o, done ) {
11738 var elem = $( this ),
11739 target = $( o.to ),
11740 targetFixed = target.css( "position" ) === "fixed",
11742 fixTop = targetFixed ? body.scrollTop() : 0,
11743 fixLeft = targetFixed ? body.scrollLeft() : 0,
11744 endPosition = target.offset(),
11746 top: endPosition.top - fixTop,
11747 left: endPosition.left - fixLeft,
11748 height: target.innerHeight(),
11749 width: target.innerWidth()
11751 startPosition = elem.offset(),
11752 transfer = $( "<div class='ui-effects-transfer'></div>" )
11753 .appendTo( document.body )
11754 .addClass( o.className )
11756 top: startPosition.top - fixTop,
11757 left: startPosition.left - fixLeft,
11758 height: elem.innerHeight(),
11759 width: elem.innerWidth(),
11760 position: targetFixed ? "fixed" : "absolute"
11762 .animate( animation, o.duration, o.easing, function() {
11770 * jQuery UI Progressbar 1.11.4
11771 * http://jqueryui.com
11773 * Copyright jQuery Foundation and other contributors
11774 * Released under the MIT license.
11775 * http://jquery.org/license
11777 * http://api.jqueryui.com/progressbar/
11781 var progressbar = $.widget( "ui.progressbar", {
11793 _create: function() {
11794 // Constrain initial value
11795 this.oldValue = this.options.value = this._constrainedValue();
11798 .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
11800 // Only set static values, aria-valuenow and aria-valuemax are
11801 // set inside _refreshValue()
11802 role: "progressbar",
11803 "aria-valuemin": this.min
11806 this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" )
11807 .appendTo( this.element );
11809 this._refreshValue();
11812 _destroy: function() {
11814 .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
11815 .removeAttr( "role" )
11816 .removeAttr( "aria-valuemin" )
11817 .removeAttr( "aria-valuemax" )
11818 .removeAttr( "aria-valuenow" );
11820 this.valueDiv.remove();
11823 value: function( newValue ) {
11824 if ( newValue === undefined ) {
11825 return this.options.value;
11828 this.options.value = this._constrainedValue( newValue );
11829 this._refreshValue();
11832 _constrainedValue: function( newValue ) {
11833 if ( newValue === undefined ) {
11834 newValue = this.options.value;
11837 this.indeterminate = newValue === false;
11840 if ( typeof newValue !== "number" ) {
11844 return this.indeterminate ? false :
11845 Math.min( this.options.max, Math.max( this.min, newValue ) );
11848 _setOptions: function( options ) {
11849 // Ensure "value" option is set after other values (like max)
11850 var value = options.value;
11851 delete options.value;
11853 this._super( options );
11855 this.options.value = this._constrainedValue( value );
11856 this._refreshValue();
11859 _setOption: function( key, value ) {
11860 if ( key === "max" ) {
11861 // Don't allow a max less than min
11862 value = Math.max( this.min, value );
11864 if ( key === "disabled" ) {
11866 .toggleClass( "ui-state-disabled", !!value )
11867 .attr( "aria-disabled", value );
11869 this._super( key, value );
11872 _percentage: function() {
11873 return this.indeterminate ? 100 : 100 * ( this.options.value - this.min ) / ( this.options.max - this.min );
11876 _refreshValue: function() {
11877 var value = this.options.value,
11878 percentage = this._percentage();
11881 .toggle( this.indeterminate || value > this.min )
11882 .toggleClass( "ui-corner-right", value === this.options.max )
11883 .width( percentage.toFixed(0) + "%" );
11885 this.element.toggleClass( "ui-progressbar-indeterminate", this.indeterminate );
11887 if ( this.indeterminate ) {
11888 this.element.removeAttr( "aria-valuenow" );
11889 if ( !this.overlayDiv ) {
11890 this.overlayDiv = $( "<div class='ui-progressbar-overlay'></div>" ).appendTo( this.valueDiv );
11893 this.element.attr({
11894 "aria-valuemax": this.options.max,
11895 "aria-valuenow": value
11897 if ( this.overlayDiv ) {
11898 this.overlayDiv.remove();
11899 this.overlayDiv = null;
11903 if ( this.oldValue !== value ) {
11904 this.oldValue = value;
11905 this._trigger( "change" );
11907 if ( value === this.options.max ) {
11908 this._trigger( "complete" );
11915 * jQuery UI Selectable 1.11.4
11916 * http://jqueryui.com
11918 * Copyright jQuery Foundation and other contributors
11919 * Released under the MIT license.
11920 * http://jquery.org/license
11922 * http://api.jqueryui.com/selectable/
11926 var selectable = $.widget("ui.selectable", $.ui.mouse, {
11933 tolerance: "touch",
11943 _create: function() {
11947 this.element.addClass("ui-selectable");
11949 this.dragged = false;
11951 // cache selectee children based on filter
11952 this.refresh = function() {
11953 selectees = $(that.options.filter, that.element[0]);
11954 selectees.addClass("ui-selectee");
11955 selectees.each(function() {
11956 var $this = $(this),
11957 pos = $this.offset();
11958 $.data(this, "selectable-item", {
11963 right: pos.left + $this.outerWidth(),
11964 bottom: pos.top + $this.outerHeight(),
11965 startselected: false,
11966 selected: $this.hasClass("ui-selected"),
11967 selecting: $this.hasClass("ui-selecting"),
11968 unselecting: $this.hasClass("ui-unselecting")
11974 this.selectees = selectees.addClass("ui-selectee");
11978 this.helper = $("<div class='ui-selectable-helper'></div>");
11981 _destroy: function() {
11983 .removeClass("ui-selectee")
11984 .removeData("selectable-item");
11986 .removeClass("ui-selectable ui-selectable-disabled");
11987 this._mouseDestroy();
11990 _mouseStart: function(event) {
11992 options = this.options;
11994 this.opos = [ event.pageX, event.pageY ];
11996 if (this.options.disabled) {
12000 this.selectees = $(options.filter, this.element[0]);
12002 this._trigger("start", event);
12004 $(options.appendTo).append(this.helper);
12005 // position helper (lasso)
12007 "left": event.pageX,
12008 "top": event.pageY,
12013 if (options.autoRefresh) {
12017 this.selectees.filter(".ui-selected").each(function() {
12018 var selectee = $.data(this, "selectable-item");
12019 selectee.startselected = true;
12020 if (!event.metaKey && !event.ctrlKey) {
12021 selectee.$element.removeClass("ui-selected");
12022 selectee.selected = false;
12023 selectee.$element.addClass("ui-unselecting");
12024 selectee.unselecting = true;
12025 // selectable UNSELECTING callback
12026 that._trigger("unselecting", event, {
12027 unselecting: selectee.element
12032 $(event.target).parents().addBack().each(function() {
12034 selectee = $.data(this, "selectable-item");
12036 doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass("ui-selected");
12038 .removeClass(doSelect ? "ui-unselecting" : "ui-selected")
12039 .addClass(doSelect ? "ui-selecting" : "ui-unselecting");
12040 selectee.unselecting = !doSelect;
12041 selectee.selecting = doSelect;
12042 selectee.selected = doSelect;
12043 // selectable (UN)SELECTING callback
12045 that._trigger("selecting", event, {
12046 selecting: selectee.element
12049 that._trigger("unselecting", event, {
12050 unselecting: selectee.element
12059 _mouseDrag: function(event) {
12061 this.dragged = true;
12063 if (this.options.disabled) {
12069 options = this.options,
12075 if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; }
12076 if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; }
12077 this.helper.css({ left: x1, top: y1, width: x2 - x1, height: y2 - y1 });
12079 this.selectees.each(function() {
12080 var selectee = $.data(this, "selectable-item"),
12083 //prevent helper from being selected if appendTo: selectable
12084 if (!selectee || selectee.element === that.element[0]) {
12088 if (options.tolerance === "touch") {
12089 hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) );
12090 } else if (options.tolerance === "fit") {
12091 hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2);
12096 if (selectee.selected) {
12097 selectee.$element.removeClass("ui-selected");
12098 selectee.selected = false;
12100 if (selectee.unselecting) {
12101 selectee.$element.removeClass("ui-unselecting");
12102 selectee.unselecting = false;
12104 if (!selectee.selecting) {
12105 selectee.$element.addClass("ui-selecting");
12106 selectee.selecting = true;
12107 // selectable SELECTING callback
12108 that._trigger("selecting", event, {
12109 selecting: selectee.element
12114 if (selectee.selecting) {
12115 if ((event.metaKey || event.ctrlKey) && selectee.startselected) {
12116 selectee.$element.removeClass("ui-selecting");
12117 selectee.selecting = false;
12118 selectee.$element.addClass("ui-selected");
12119 selectee.selected = true;
12121 selectee.$element.removeClass("ui-selecting");
12122 selectee.selecting = false;
12123 if (selectee.startselected) {
12124 selectee.$element.addClass("ui-unselecting");
12125 selectee.unselecting = true;
12127 // selectable UNSELECTING callback
12128 that._trigger("unselecting", event, {
12129 unselecting: selectee.element
12133 if (selectee.selected) {
12134 if (!event.metaKey && !event.ctrlKey && !selectee.startselected) {
12135 selectee.$element.removeClass("ui-selected");
12136 selectee.selected = false;
12138 selectee.$element.addClass("ui-unselecting");
12139 selectee.unselecting = true;
12140 // selectable UNSELECTING callback
12141 that._trigger("unselecting", event, {
12142 unselecting: selectee.element
12152 _mouseStop: function(event) {
12155 this.dragged = false;
12157 $(".ui-unselecting", this.element[0]).each(function() {
12158 var selectee = $.data(this, "selectable-item");
12159 selectee.$element.removeClass("ui-unselecting");
12160 selectee.unselecting = false;
12161 selectee.startselected = false;
12162 that._trigger("unselected", event, {
12163 unselected: selectee.element
12166 $(".ui-selecting", this.element[0]).each(function() {
12167 var selectee = $.data(this, "selectable-item");
12168 selectee.$element.removeClass("ui-selecting").addClass("ui-selected");
12169 selectee.selecting = false;
12170 selectee.selected = true;
12171 selectee.startselected = true;
12172 that._trigger("selected", event, {
12173 selected: selectee.element
12176 this._trigger("stop", event);
12178 this.helper.remove();
12187 * jQuery UI Selectmenu 1.11.4
12188 * http://jqueryui.com
12190 * Copyright jQuery Foundation and other contributors
12191 * Released under the MIT license.
12192 * http://jquery.org/license
12194 * http://api.jqueryui.com/selectmenu
12198 var selectmenu = $.widget( "ui.selectmenu", {
12200 defaultElement: "<select>",
12205 button: "ui-icon-triangle-1-s"
12222 _create: function() {
12223 var selectmenuId = this.element.uniqueId().attr( "id" );
12225 element: selectmenuId,
12226 button: selectmenuId + "-button",
12227 menu: selectmenuId + "-menu"
12230 this._drawButton();
12233 if ( this.options.disabled ) {
12238 _drawButton: function() {
12241 // Associate existing label with the new button
12242 this.label = $( "label[for='" + this.ids.element + "']" ).attr( "for", this.ids.button );
12243 this._on( this.label, {
12244 click: function( event ) {
12245 this.button.focus();
12246 event.preventDefault();
12250 // Hide original select element
12251 this.element.hide();
12254 this.button = $( "<span>", {
12255 "class": "ui-selectmenu-button ui-widget ui-state-default ui-corner-all",
12256 tabindex: this.options.disabled ? -1 : 0,
12257 id: this.ids.button,
12259 "aria-expanded": "false",
12260 "aria-autocomplete": "list",
12261 "aria-owns": this.ids.menu,
12262 "aria-haspopup": "true"
12264 .insertAfter( this.element );
12267 "class": "ui-icon " + this.options.icons.button
12269 .prependTo( this.button );
12271 this.buttonText = $( "<span>", {
12272 "class": "ui-selectmenu-text"
12274 .appendTo( this.button );
12276 this._setText( this.buttonText, this.element.find( "option:selected" ).text() );
12277 this._resizeButton();
12279 this._on( this.button, this._buttonEvents );
12280 this.button.one( "focusin", function() {
12282 // Delay rendering the menu items until the button receives focus.
12283 // The menu may have already been rendered via a programmatic open.
12284 if ( !that.menuItems ) {
12285 that._refreshMenu();
12288 this._hoverable( this.button );
12289 this._focusable( this.button );
12292 _drawMenu: function() {
12296 this.menu = $( "<ul>", {
12297 "aria-hidden": "true",
12298 "aria-labelledby": this.ids.button,
12303 this.menuWrap = $( "<div>", {
12304 "class": "ui-selectmenu-menu ui-front"
12306 .append( this.menu )
12307 .appendTo( this._appendTo() );
12309 // Initialize menu widget
12310 this.menuInstance = this.menu
12313 select: function( event, ui ) {
12314 event.preventDefault();
12317 // If the item was selected via a click, the text selection
12318 // will be destroyed in IE
12319 that._setSelection();
12321 that._select( ui.item.data( "ui-selectmenu-item" ), event );
12323 focus: function( event, ui ) {
12324 var item = ui.item.data( "ui-selectmenu-item" );
12326 // Prevent inital focus from firing and check if its a newly focused item
12327 if ( that.focusIndex != null && item.index !== that.focusIndex ) {
12328 that._trigger( "focus", event, { item: item } );
12329 if ( !that.isOpen ) {
12330 that._select( item, event );
12333 that.focusIndex = item.index;
12335 that.button.attr( "aria-activedescendant",
12336 that.menuItems.eq( item.index ).attr( "id" ) );
12339 .menu( "instance" );
12341 // Adjust menu styles to dropdown
12343 .addClass( "ui-corner-bottom" )
12344 .removeClass( "ui-corner-all" );
12346 // Don't close the menu on mouseleave
12347 this.menuInstance._off( this.menu, "mouseleave" );
12349 // Cancel the menu's collapseAll on document click
12350 this.menuInstance._closeOnDocumentClick = function() {
12354 // Selects often contain empty items, but never contain dividers
12355 this.menuInstance._isDivider = function() {
12360 refresh: function() {
12361 this._refreshMenu();
12362 this._setText( this.buttonText, this._getSelectedItem().text() );
12363 if ( !this.options.width ) {
12364 this._resizeButton();
12368 _refreshMenu: function() {
12372 options = this.element.find( "option" );
12374 if ( !options.length ) {
12378 this._parseOptions( options );
12379 this._renderMenu( this.menu, this.items );
12381 this.menuInstance.refresh();
12382 this.menuItems = this.menu.find( "li" ).not( ".ui-selectmenu-optgroup" );
12384 item = this._getSelectedItem();
12386 // Update the menu to have the correct item focused
12387 this.menuInstance.focus( null, item );
12388 this._setAria( item.data( "ui-selectmenu-item" ) );
12390 // Set disabled state
12391 this._setOption( "disabled", this.element.prop( "disabled" ) );
12394 open: function( event ) {
12395 if ( this.options.disabled ) {
12399 // If this is the first time the menu is being opened, render the items
12400 if ( !this.menuItems ) {
12401 this._refreshMenu();
12404 // Menu clears focus on close, reset focus to selected item
12405 this.menu.find( ".ui-state-focus" ).removeClass( "ui-state-focus" );
12406 this.menuInstance.focus( null, this._getSelectedItem() );
12409 this.isOpen = true;
12410 this._toggleAttr();
12411 this._resizeMenu();
12414 this._on( this.document, this._documentClick );
12416 this._trigger( "open", event );
12419 _position: function() {
12420 this.menuWrap.position( $.extend( { of: this.button }, this.options.position ) );
12423 close: function( event ) {
12424 if ( !this.isOpen ) {
12428 this.isOpen = false;
12429 this._toggleAttr();
12432 this._off( this.document );
12434 this._trigger( "close", event );
12437 widget: function() {
12438 return this.button;
12441 menuWidget: function() {
12445 _renderMenu: function( ul, items ) {
12447 currentOptgroup = "";
12449 $.each( items, function( index, item ) {
12450 if ( item.optgroup !== currentOptgroup ) {
12452 "class": "ui-selectmenu-optgroup ui-menu-divider" +
12453 ( item.element.parent( "optgroup" ).prop( "disabled" ) ?
12454 " ui-state-disabled" :
12456 text: item.optgroup
12460 currentOptgroup = item.optgroup;
12463 that._renderItemData( ul, item );
12467 _renderItemData: function( ul, item ) {
12468 return this._renderItem( ul, item ).data( "ui-selectmenu-item", item );
12471 _renderItem: function( ul, item ) {
12472 var li = $( "<li>" );
12474 if ( item.disabled ) {
12475 li.addClass( "ui-state-disabled" );
12477 this._setText( li, item.label );
12479 return li.appendTo( ul );
12482 _setText: function( element, value ) {
12484 element.text( value );
12486 element.html( " " );
12490 _move: function( direction, event ) {
12492 filter = ".ui-menu-item";
12494 if ( this.isOpen ) {
12495 item = this.menuItems.eq( this.focusIndex );
12497 item = this.menuItems.eq( this.element[ 0 ].selectedIndex );
12498 filter += ":not(.ui-state-disabled)";
12501 if ( direction === "first" || direction === "last" ) {
12502 next = item[ direction === "first" ? "prevAll" : "nextAll" ]( filter ).eq( -1 );
12504 next = item[ direction + "All" ]( filter ).eq( 0 );
12507 if ( next.length ) {
12508 this.menuInstance.focus( event, next );
12512 _getSelectedItem: function() {
12513 return this.menuItems.eq( this.element[ 0 ].selectedIndex );
12516 _toggle: function( event ) {
12517 this[ this.isOpen ? "close" : "open" ]( event );
12520 _setSelection: function() {
12523 if ( !this.range ) {
12527 if ( window.getSelection ) {
12528 selection = window.getSelection();
12529 selection.removeAllRanges();
12530 selection.addRange( this.range );
12534 this.range.select();
12538 // Setting the text selection kills the button focus in IE, but
12539 // restoring the focus doesn't kill the selection.
12540 this.button.focus();
12544 mousedown: function( event ) {
12545 if ( !this.isOpen ) {
12549 if ( !$( event.target ).closest( ".ui-selectmenu-menu, #" + this.ids.button ).length ) {
12550 this.close( event );
12557 // Prevent text selection from being reset when interacting with the selectmenu (#10144)
12558 mousedown: function() {
12561 if ( window.getSelection ) {
12562 selection = window.getSelection();
12563 if ( selection.rangeCount ) {
12564 this.range = selection.getRangeAt( 0 );
12569 this.range = document.selection.createRange();
12573 click: function( event ) {
12574 this._setSelection();
12575 this._toggle( event );
12578 keydown: function( event ) {
12579 var preventDefault = true;
12580 switch ( event.keyCode ) {
12581 case $.ui.keyCode.TAB:
12582 case $.ui.keyCode.ESCAPE:
12583 this.close( event );
12584 preventDefault = false;
12586 case $.ui.keyCode.ENTER:
12587 if ( this.isOpen ) {
12588 this._selectFocusedItem( event );
12591 case $.ui.keyCode.UP:
12592 if ( event.altKey ) {
12593 this._toggle( event );
12595 this._move( "prev", event );
12598 case $.ui.keyCode.DOWN:
12599 if ( event.altKey ) {
12600 this._toggle( event );
12602 this._move( "next", event );
12605 case $.ui.keyCode.SPACE:
12606 if ( this.isOpen ) {
12607 this._selectFocusedItem( event );
12609 this._toggle( event );
12612 case $.ui.keyCode.LEFT:
12613 this._move( "prev", event );
12615 case $.ui.keyCode.RIGHT:
12616 this._move( "next", event );
12618 case $.ui.keyCode.HOME:
12619 case $.ui.keyCode.PAGE_UP:
12620 this._move( "first", event );
12622 case $.ui.keyCode.END:
12623 case $.ui.keyCode.PAGE_DOWN:
12624 this._move( "last", event );
12627 this.menu.trigger( event );
12628 preventDefault = false;
12631 if ( preventDefault ) {
12632 event.preventDefault();
12637 _selectFocusedItem: function( event ) {
12638 var item = this.menuItems.eq( this.focusIndex );
12639 if ( !item.hasClass( "ui-state-disabled" ) ) {
12640 this._select( item.data( "ui-selectmenu-item" ), event );
12644 _select: function( item, event ) {
12645 var oldIndex = this.element[ 0 ].selectedIndex;
12647 // Change native select element
12648 this.element[ 0 ].selectedIndex = item.index;
12649 this._setText( this.buttonText, item.label );
12650 this._setAria( item );
12651 this._trigger( "select", event, { item: item } );
12653 if ( item.index !== oldIndex ) {
12654 this._trigger( "change", event, { item: item } );
12657 this.close( event );
12660 _setAria: function( item ) {
12661 var id = this.menuItems.eq( item.index ).attr( "id" );
12664 "aria-labelledby": id,
12665 "aria-activedescendant": id
12667 this.menu.attr( "aria-activedescendant", id );
12670 _setOption: function( key, value ) {
12671 if ( key === "icons" ) {
12672 this.button.find( "span.ui-icon" )
12673 .removeClass( this.options.icons.button )
12674 .addClass( value.button );
12677 this._super( key, value );
12679 if ( key === "appendTo" ) {
12680 this.menuWrap.appendTo( this._appendTo() );
12683 if ( key === "disabled" ) {
12684 this.menuInstance.option( "disabled", value );
12686 .toggleClass( "ui-state-disabled", value )
12687 .attr( "aria-disabled", value );
12689 this.element.prop( "disabled", value );
12691 this.button.attr( "tabindex", -1 );
12694 this.button.attr( "tabindex", 0 );
12698 if ( key === "width" ) {
12699 this._resizeButton();
12703 _appendTo: function() {
12704 var element = this.options.appendTo;
12707 element = element.jquery || element.nodeType ?
12709 this.document.find( element ).eq( 0 );
12712 if ( !element || !element[ 0 ] ) {
12713 element = this.element.closest( ".ui-front" );
12716 if ( !element.length ) {
12717 element = this.document[ 0 ].body;
12723 _toggleAttr: function() {
12725 .toggleClass( "ui-corner-top", this.isOpen )
12726 .toggleClass( "ui-corner-all", !this.isOpen )
12727 .attr( "aria-expanded", this.isOpen );
12728 this.menuWrap.toggleClass( "ui-selectmenu-open", this.isOpen );
12729 this.menu.attr( "aria-hidden", !this.isOpen );
12732 _resizeButton: function() {
12733 var width = this.options.width;
12736 width = this.element.show().outerWidth();
12737 this.element.hide();
12740 this.button.outerWidth( width );
12743 _resizeMenu: function() {
12744 this.menu.outerWidth( Math.max(
12745 this.button.outerWidth(),
12748 // IE10 wraps long text (possibly a rounding bug)
12749 // so we add 1px to avoid the wrapping
12750 this.menu.width( "" ).outerWidth() + 1
12754 _getCreateOptions: function() {
12755 return { disabled: this.element.prop( "disabled" ) };
12758 _parseOptions: function( options ) {
12760 options.each(function( index, item ) {
12761 var option = $( item ),
12762 optgroup = option.parent( "optgroup" );
12766 value: option.val(),
12767 label: option.text(),
12768 optgroup: optgroup.attr( "label" ) || "",
12769 disabled: optgroup.prop( "disabled" ) || option.prop( "disabled" )
12775 _destroy: function() {
12776 this.menuWrap.remove();
12777 this.button.remove();
12778 this.element.show();
12779 this.element.removeUniqueId();
12780 this.label.attr( "for", this.ids.element );
12786 * jQuery UI Slider 1.11.4
12787 * http://jqueryui.com
12789 * Copyright jQuery Foundation and other contributors
12790 * Released under the MIT license.
12791 * http://jquery.org/license
12793 * http://api.jqueryui.com/slider/
12797 var slider = $.widget( "ui.slider", $.ui.mouse, {
12799 widgetEventPrefix: "slide",
12806 orientation: "horizontal",
12819 // number of pages in a slider
12820 // (how many times can you page up/down to go through the whole range)
12823 _create: function() {
12824 this._keySliding = false;
12825 this._mouseSliding = false;
12826 this._animateOff = true;
12827 this._handleIndex = null;
12828 this._detectOrientation();
12830 this._calculateNewMax();
12833 .addClass( "ui-slider" +
12834 " ui-slider-" + this.orientation +
12836 " ui-widget-content" +
12840 this._setOption( "disabled", this.options.disabled );
12842 this._animateOff = false;
12845 _refresh: function() {
12846 this._createRange();
12847 this._createHandles();
12848 this._setupEvents();
12849 this._refreshValue();
12852 _createHandles: function() {
12853 var i, handleCount,
12854 options = this.options,
12855 existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ),
12856 handle = "<span class='ui-slider-handle ui-state-default ui-corner-all' tabindex='0'></span>",
12859 handleCount = ( options.values && options.values.length ) || 1;
12861 if ( existingHandles.length > handleCount ) {
12862 existingHandles.slice( handleCount ).remove();
12863 existingHandles = existingHandles.slice( 0, handleCount );
12866 for ( i = existingHandles.length; i < handleCount; i++ ) {
12867 handles.push( handle );
12870 this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
12872 this.handle = this.handles.eq( 0 );
12874 this.handles.each(function( i ) {
12875 $( this ).data( "ui-slider-handle-index", i );
12879 _createRange: function() {
12880 var options = this.options,
12883 if ( options.range ) {
12884 if ( options.range === true ) {
12885 if ( !options.values ) {
12886 options.values = [ this._valueMin(), this._valueMin() ];
12887 } else if ( options.values.length && options.values.length !== 2 ) {
12888 options.values = [ options.values[0], options.values[0] ];
12889 } else if ( $.isArray( options.values ) ) {
12890 options.values = options.values.slice(0);
12894 if ( !this.range || !this.range.length ) {
12895 this.range = $( "<div></div>" )
12896 .appendTo( this.element );
12898 classes = "ui-slider-range" +
12899 // note: this isn't the most fittingly semantic framework class for this element,
12900 // but worked best visually with a variety of themes
12901 " ui-widget-header ui-corner-all";
12903 this.range.removeClass( "ui-slider-range-min ui-slider-range-max" )
12904 // Handle range switching from true to min/max
12911 this.range.addClass( classes +
12912 ( ( options.range === "min" || options.range === "max" ) ? " ui-slider-range-" + options.range : "" ) );
12914 if ( this.range ) {
12915 this.range.remove();
12921 _setupEvents: function() {
12922 this._off( this.handles );
12923 this._on( this.handles, this._handleEvents );
12924 this._hoverable( this.handles );
12925 this._focusable( this.handles );
12928 _destroy: function() {
12929 this.handles.remove();
12930 if ( this.range ) {
12931 this.range.remove();
12935 .removeClass( "ui-slider" +
12936 " ui-slider-horizontal" +
12937 " ui-slider-vertical" +
12939 " ui-widget-content" +
12940 " ui-corner-all" );
12942 this._mouseDestroy();
12945 _mouseCapture: function( event ) {
12946 var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
12950 if ( o.disabled ) {
12954 this.elementSize = {
12955 width: this.element.outerWidth(),
12956 height: this.element.outerHeight()
12958 this.elementOffset = this.element.offset();
12960 position = { x: event.pageX, y: event.pageY };
12961 normValue = this._normValueFromMouse( position );
12962 distance = this._valueMax() - this._valueMin() + 1;
12963 this.handles.each(function( i ) {
12964 var thisDistance = Math.abs( normValue - that.values(i) );
12965 if (( distance > thisDistance ) ||
12966 ( distance === thisDistance &&
12967 (i === that._lastChangedValue || that.values(i) === o.min ))) {
12968 distance = thisDistance;
12969 closestHandle = $( this );
12974 allowed = this._start( event, index );
12975 if ( allowed === false ) {
12978 this._mouseSliding = true;
12980 this._handleIndex = index;
12983 .addClass( "ui-state-active" )
12986 offset = closestHandle.offset();
12987 mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
12988 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
12989 left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
12990 top: event.pageY - offset.top -
12991 ( closestHandle.height() / 2 ) -
12992 ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) -
12993 ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) +
12994 ( parseInt( closestHandle.css("marginTop"), 10 ) || 0)
12997 if ( !this.handles.hasClass( "ui-state-hover" ) ) {
12998 this._slide( event, index, normValue );
13000 this._animateOff = true;
13004 _mouseStart: function() {
13008 _mouseDrag: function( event ) {
13009 var position = { x: event.pageX, y: event.pageY },
13010 normValue = this._normValueFromMouse( position );
13012 this._slide( event, this._handleIndex, normValue );
13017 _mouseStop: function( event ) {
13018 this.handles.removeClass( "ui-state-active" );
13019 this._mouseSliding = false;
13021 this._stop( event, this._handleIndex );
13022 this._change( event, this._handleIndex );
13024 this._handleIndex = null;
13025 this._clickOffset = null;
13026 this._animateOff = false;
13031 _detectOrientation: function() {
13032 this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
13035 _normValueFromMouse: function( position ) {
13042 if ( this.orientation === "horizontal" ) {
13043 pixelTotal = this.elementSize.width;
13044 pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
13046 pixelTotal = this.elementSize.height;
13047 pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );
13050 percentMouse = ( pixelMouse / pixelTotal );
13051 if ( percentMouse > 1 ) {
13054 if ( percentMouse < 0 ) {
13057 if ( this.orientation === "vertical" ) {
13058 percentMouse = 1 - percentMouse;
13061 valueTotal = this._valueMax() - this._valueMin();
13062 valueMouse = this._valueMin() + percentMouse * valueTotal;
13064 return this._trimAlignValue( valueMouse );
13067 _start: function( event, index ) {
13069 handle: this.handles[ index ],
13070 value: this.value()
13072 if ( this.options.values && this.options.values.length ) {
13073 uiHash.value = this.values( index );
13074 uiHash.values = this.values();
13076 return this._trigger( "start", event, uiHash );
13079 _slide: function( event, index, newVal ) {
13084 if ( this.options.values && this.options.values.length ) {
13085 otherVal = this.values( index ? 0 : 1 );
13087 if ( ( this.options.values.length === 2 && this.options.range === true ) &&
13088 ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )
13093 if ( newVal !== this.values( index ) ) {
13094 newValues = this.values();
13095 newValues[ index ] = newVal;
13096 // A slide can be canceled by returning false from the slide callback
13097 allowed = this._trigger( "slide", event, {
13098 handle: this.handles[ index ],
13102 otherVal = this.values( index ? 0 : 1 );
13103 if ( allowed !== false ) {
13104 this.values( index, newVal );
13108 if ( newVal !== this.value() ) {
13109 // A slide can be canceled by returning false from the slide callback
13110 allowed = this._trigger( "slide", event, {
13111 handle: this.handles[ index ],
13114 if ( allowed !== false ) {
13115 this.value( newVal );
13121 _stop: function( event, index ) {
13123 handle: this.handles[ index ],
13124 value: this.value()
13126 if ( this.options.values && this.options.values.length ) {
13127 uiHash.value = this.values( index );
13128 uiHash.values = this.values();
13131 this._trigger( "stop", event, uiHash );
13134 _change: function( event, index ) {
13135 if ( !this._keySliding && !this._mouseSliding ) {
13137 handle: this.handles[ index ],
13138 value: this.value()
13140 if ( this.options.values && this.options.values.length ) {
13141 uiHash.value = this.values( index );
13142 uiHash.values = this.values();
13145 //store the last changed value index for reference when handles overlap
13146 this._lastChangedValue = index;
13148 this._trigger( "change", event, uiHash );
13152 value: function( newValue ) {
13153 if ( arguments.length ) {
13154 this.options.value = this._trimAlignValue( newValue );
13155 this._refreshValue();
13156 this._change( null, 0 );
13160 return this._value();
13163 values: function( index, newValue ) {
13168 if ( arguments.length > 1 ) {
13169 this.options.values[ index ] = this._trimAlignValue( newValue );
13170 this._refreshValue();
13171 this._change( null, index );
13175 if ( arguments.length ) {
13176 if ( $.isArray( arguments[ 0 ] ) ) {
13177 vals = this.options.values;
13178 newValues = arguments[ 0 ];
13179 for ( i = 0; i < vals.length; i += 1 ) {
13180 vals[ i ] = this._trimAlignValue( newValues[ i ] );
13181 this._change( null, i );
13183 this._refreshValue();
13185 if ( this.options.values && this.options.values.length ) {
13186 return this._values( index );
13188 return this.value();
13192 return this._values();
13196 _setOption: function( key, value ) {
13200 if ( key === "range" && this.options.range === true ) {
13201 if ( value === "min" ) {
13202 this.options.value = this._values( 0 );
13203 this.options.values = null;
13204 } else if ( value === "max" ) {
13205 this.options.value = this._values( this.options.values.length - 1 );
13206 this.options.values = null;
13210 if ( $.isArray( this.options.values ) ) {
13211 valsLength = this.options.values.length;
13214 if ( key === "disabled" ) {
13215 this.element.toggleClass( "ui-state-disabled", !!value );
13218 this._super( key, value );
13221 case "orientation":
13222 this._detectOrientation();
13224 .removeClass( "ui-slider-horizontal ui-slider-vertical" )
13225 .addClass( "ui-slider-" + this.orientation );
13226 this._refreshValue();
13228 // Reset positioning from previous orientation
13229 this.handles.css( value === "horizontal" ? "bottom" : "left", "" );
13232 this._animateOff = true;
13233 this._refreshValue();
13234 this._change( null, 0 );
13235 this._animateOff = false;
13238 this._animateOff = true;
13239 this._refreshValue();
13240 for ( i = 0; i < valsLength; i += 1 ) {
13241 this._change( null, i );
13243 this._animateOff = false;
13248 this._animateOff = true;
13249 this._calculateNewMax();
13250 this._refreshValue();
13251 this._animateOff = false;
13254 this._animateOff = true;
13256 this._animateOff = false;
13261 //internal value getter
13262 // _value() returns value trimmed by min and max, aligned by step
13263 _value: function() {
13264 var val = this.options.value;
13265 val = this._trimAlignValue( val );
13270 //internal values getter
13271 // _values() returns array of values trimmed by min and max, aligned by step
13272 // _values( index ) returns single value trimmed by min and max, aligned by step
13273 _values: function( index ) {
13278 if ( arguments.length ) {
13279 val = this.options.values[ index ];
13280 val = this._trimAlignValue( val );
13283 } else if ( this.options.values && this.options.values.length ) {
13284 // .slice() creates a copy of the array
13285 // this copy gets trimmed by min and max and then returned
13286 vals = this.options.values.slice();
13287 for ( i = 0; i < vals.length; i += 1) {
13288 vals[ i ] = this._trimAlignValue( vals[ i ] );
13297 // returns the step-aligned value that val is closest to, between (inclusive) min and max
13298 _trimAlignValue: function( val ) {
13299 if ( val <= this._valueMin() ) {
13300 return this._valueMin();
13302 if ( val >= this._valueMax() ) {
13303 return this._valueMax();
13305 var step = ( this.options.step > 0 ) ? this.options.step : 1,
13306 valModStep = (val - this._valueMin()) % step,
13307 alignValue = val - valModStep;
13309 if ( Math.abs(valModStep) * 2 >= step ) {
13310 alignValue += ( valModStep > 0 ) ? step : ( -step );
13313 // Since JavaScript has problems with large floats, round
13314 // the final value to 5 digits after the decimal point (see #4124)
13315 return parseFloat( alignValue.toFixed(5) );
13318 _calculateNewMax: function() {
13319 var max = this.options.max,
13320 min = this._valueMin(),
13321 step = this.options.step,
13322 aboveMin = Math.floor( ( +( max - min ).toFixed( this._precision() ) ) / step ) * step;
13323 max = aboveMin + min;
13324 this.max = parseFloat( max.toFixed( this._precision() ) );
13327 _precision: function() {
13328 var precision = this._precisionOf( this.options.step );
13329 if ( this.options.min !== null ) {
13330 precision = Math.max( precision, this._precisionOf( this.options.min ) );
13335 _precisionOf: function( num ) {
13336 var str = num.toString(),
13337 decimal = str.indexOf( "." );
13338 return decimal === -1 ? 0 : str.length - decimal - 1;
13341 _valueMin: function() {
13342 return this.options.min;
13345 _valueMax: function() {
13349 _refreshValue: function() {
13350 var lastValPercent, valPercent, value, valueMin, valueMax,
13351 oRange = this.options.range,
13354 animate = ( !this._animateOff ) ? o.animate : false,
13357 if ( this.options.values && this.options.values.length ) {
13358 this.handles.each(function( i ) {
13359 valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100;
13360 _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
13361 $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
13362 if ( that.options.range === true ) {
13363 if ( that.orientation === "horizontal" ) {
13365 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate );
13368 that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
13372 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate );
13375 that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
13379 lastValPercent = valPercent;
13382 value = this.value();
13383 valueMin = this._valueMin();
13384 valueMax = this._valueMax();
13385 valPercent = ( valueMax !== valueMin ) ?
13386 ( value - valueMin ) / ( valueMax - valueMin ) * 100 :
13388 _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
13389 this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
13391 if ( oRange === "min" && this.orientation === "horizontal" ) {
13392 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate );
13394 if ( oRange === "max" && this.orientation === "horizontal" ) {
13395 this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
13397 if ( oRange === "min" && this.orientation === "vertical" ) {
13398 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate );
13400 if ( oRange === "max" && this.orientation === "vertical" ) {
13401 this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
13407 keydown: function( event ) {
13408 var allowed, curVal, newVal, step,
13409 index = $( event.target ).data( "ui-slider-handle-index" );
13411 switch ( event.keyCode ) {
13412 case $.ui.keyCode.HOME:
13413 case $.ui.keyCode.END:
13414 case $.ui.keyCode.PAGE_UP:
13415 case $.ui.keyCode.PAGE_DOWN:
13416 case $.ui.keyCode.UP:
13417 case $.ui.keyCode.RIGHT:
13418 case $.ui.keyCode.DOWN:
13419 case $.ui.keyCode.LEFT:
13420 event.preventDefault();
13421 if ( !this._keySliding ) {
13422 this._keySliding = true;
13423 $( event.target ).addClass( "ui-state-active" );
13424 allowed = this._start( event, index );
13425 if ( allowed === false ) {
13432 step = this.options.step;
13433 if ( this.options.values && this.options.values.length ) {
13434 curVal = newVal = this.values( index );
13436 curVal = newVal = this.value();
13439 switch ( event.keyCode ) {
13440 case $.ui.keyCode.HOME:
13441 newVal = this._valueMin();
13443 case $.ui.keyCode.END:
13444 newVal = this._valueMax();
13446 case $.ui.keyCode.PAGE_UP:
13447 newVal = this._trimAlignValue(
13448 curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages )
13451 case $.ui.keyCode.PAGE_DOWN:
13452 newVal = this._trimAlignValue(
13453 curVal - ( (this._valueMax() - this._valueMin()) / this.numPages ) );
13455 case $.ui.keyCode.UP:
13456 case $.ui.keyCode.RIGHT:
13457 if ( curVal === this._valueMax() ) {
13460 newVal = this._trimAlignValue( curVal + step );
13462 case $.ui.keyCode.DOWN:
13463 case $.ui.keyCode.LEFT:
13464 if ( curVal === this._valueMin() ) {
13467 newVal = this._trimAlignValue( curVal - step );
13471 this._slide( event, index, newVal );
13473 keyup: function( event ) {
13474 var index = $( event.target ).data( "ui-slider-handle-index" );
13476 if ( this._keySliding ) {
13477 this._keySliding = false;
13478 this._stop( event, index );
13479 this._change( event, index );
13480 $( event.target ).removeClass( "ui-state-active" );
13488 * jQuery UI Sortable 1.11.4
13489 * http://jqueryui.com
13491 * Copyright jQuery Foundation and other contributors
13492 * Released under the MIT license.
13493 * http://jquery.org/license
13495 * http://api.jqueryui.com/sortable/
13499 var sortable = $.widget("ui.sortable", $.ui.mouse, {
13501 widgetEventPrefix: "sort",
13504 appendTo: "parent",
13506 connectWith: false,
13507 containment: false,
13511 forcePlaceholderSize: false,
13512 forceHelperSize: false,
13515 helper: "original",
13518 placeholder: false,
13521 scrollSensitivity: 20,
13524 tolerance: "intersect",
13542 _isOverAxis: function( x, reference, size ) {
13543 return ( x >= reference ) && ( x < ( reference + size ) );
13546 _isFloating: function( item ) {
13547 return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display"));
13550 _create: function() {
13551 this.containerCache = {};
13552 this.element.addClass("ui-sortable");
13557 //Let's determine the parent's offset
13558 this.offset = this.element.offset();
13560 //Initialize mouse events for interaction
13563 this._setHandleClassName();
13565 //We're ready to go
13570 _setOption: function( key, value ) {
13571 this._super( key, value );
13573 if ( key === "handle" ) {
13574 this._setHandleClassName();
13578 _setHandleClassName: function() {
13579 this.element.find( ".ui-sortable-handle" ).removeClass( "ui-sortable-handle" );
13580 $.each( this.items, function() {
13581 ( this.instance.options.handle ?
13582 this.item.find( this.instance.options.handle ) : this.item )
13583 .addClass( "ui-sortable-handle" );
13587 _destroy: function() {
13589 .removeClass( "ui-sortable ui-sortable-disabled" )
13590 .find( ".ui-sortable-handle" )
13591 .removeClass( "ui-sortable-handle" );
13592 this._mouseDestroy();
13594 for ( var i = this.items.length - 1; i >= 0; i-- ) {
13595 this.items[i].item.removeData(this.widgetName + "-item");
13601 _mouseCapture: function(event, overrideHandle) {
13602 var currentItem = null,
13603 validHandle = false,
13606 if (this.reverting) {
13610 if(this.options.disabled || this.options.type === "static") {
13614 //We have to refresh the items data once first
13615 this._refreshItems(event);
13617 //Find out if the clicked node (or one of its parents) is a actual item in this.items
13618 $(event.target).parents().each(function() {
13619 if($.data(this, that.widgetName + "-item") === that) {
13620 currentItem = $(this);
13624 if($.data(event.target, that.widgetName + "-item") === that) {
13625 currentItem = $(event.target);
13631 if(this.options.handle && !overrideHandle) {
13632 $(this.options.handle, currentItem).find("*").addBack().each(function() {
13633 if(this === event.target) {
13634 validHandle = true;
13642 this.currentItem = currentItem;
13643 this._removeCurrentsFromItems();
13648 _mouseStart: function(event, overrideHandle, noActivation) {
13653 this.currentContainer = this;
13655 //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
13656 this.refreshPositions();
13658 //Create and append the visible helper
13659 this.helper = this._createHelper(event);
13661 //Cache the helper size
13662 this._cacheHelperProportions();
13665 * - Position generation -
13666 * This block generates everything position related - it's the core of draggables.
13669 //Cache the margins of the original element
13670 this._cacheMargins();
13672 //Get the next scrolling parent
13673 this.scrollParent = this.helper.scrollParent();
13675 //The element's absolute position on the page minus margins
13676 this.offset = this.currentItem.offset();
13678 top: this.offset.top - this.margins.top,
13679 left: this.offset.left - this.margins.left
13682 $.extend(this.offset, {
13683 click: { //Where the click happened, relative to the element
13684 left: event.pageX - this.offset.left,
13685 top: event.pageY - this.offset.top
13687 parent: this._getParentOffset(),
13688 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
13691 // Only after we got the offset, we can change the helper's position to absolute
13692 // TODO: Still need to figure out a way to make relative sorting possible
13693 this.helper.css("position", "absolute");
13694 this.cssPosition = this.helper.css("position");
13696 //Generate the original position
13697 this.originalPosition = this._generatePosition(event);
13698 this.originalPageX = event.pageX;
13699 this.originalPageY = event.pageY;
13701 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
13702 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
13704 //Cache the former DOM position
13705 this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };
13707 //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
13708 if(this.helper[0] !== this.currentItem[0]) {
13709 this.currentItem.hide();
13712 //Create the placeholder
13713 this._createPlaceholder();
13715 //Set a containment if given in the options
13716 if(o.containment) {
13717 this._setContainment();
13720 if( o.cursor && o.cursor !== "auto" ) { // cursor option
13721 body = this.document.find( "body" );
13724 this.storedCursor = body.css( "cursor" );
13725 body.css( "cursor", o.cursor );
13727 this.storedStylesheet = $( "<style>*{ cursor: "+o.cursor+" !important; }</style>" ).appendTo( body );
13730 if(o.opacity) { // opacity option
13731 if (this.helper.css("opacity")) {
13732 this._storedOpacity = this.helper.css("opacity");
13734 this.helper.css("opacity", o.opacity);
13737 if(o.zIndex) { // zIndex option
13738 if (this.helper.css("zIndex")) {
13739 this._storedZIndex = this.helper.css("zIndex");
13741 this.helper.css("zIndex", o.zIndex);
13744 //Prepare scrolling
13745 if(this.scrollParent[0] !== this.document[0] && this.scrollParent[0].tagName !== "HTML") {
13746 this.overflowOffset = this.scrollParent.offset();
13750 this._trigger("start", event, this._uiHash());
13752 //Recache the helper size
13753 if(!this._preserveHelperProportions) {
13754 this._cacheHelperProportions();
13758 //Post "activate" events to possible containers
13759 if( !noActivation ) {
13760 for ( i = this.containers.length - 1; i >= 0; i-- ) {
13761 this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
13765 //Prepare possible droppables
13766 if($.ui.ddmanager) {
13767 $.ui.ddmanager.current = this;
13770 if ($.ui.ddmanager && !o.dropBehaviour) {
13771 $.ui.ddmanager.prepareOffsets(this, event);
13774 this.dragging = true;
13776 this.helper.addClass("ui-sortable-helper");
13777 this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
13782 _mouseDrag: function(event) {
13783 var i, item, itemElement, intersection,
13787 //Compute the helpers position
13788 this.position = this._generatePosition(event);
13789 this.positionAbs = this._convertPositionTo("absolute");
13791 if (!this.lastPositionAbs) {
13792 this.lastPositionAbs = this.positionAbs;
13796 if(this.options.scroll) {
13797 if(this.scrollParent[0] !== this.document[0] && this.scrollParent[0].tagName !== "HTML") {
13799 if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
13800 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
13801 } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) {
13802 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
13805 if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
13806 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
13807 } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) {
13808 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
13813 if(event.pageY - this.document.scrollTop() < o.scrollSensitivity) {
13814 scrolled = this.document.scrollTop(this.document.scrollTop() - o.scrollSpeed);
13815 } else if(this.window.height() - (event.pageY - this.document.scrollTop()) < o.scrollSensitivity) {
13816 scrolled = this.document.scrollTop(this.document.scrollTop() + o.scrollSpeed);
13819 if(event.pageX - this.document.scrollLeft() < o.scrollSensitivity) {
13820 scrolled = this.document.scrollLeft(this.document.scrollLeft() - o.scrollSpeed);
13821 } else if(this.window.width() - (event.pageX - this.document.scrollLeft()) < o.scrollSensitivity) {
13822 scrolled = this.document.scrollLeft(this.document.scrollLeft() + o.scrollSpeed);
13827 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
13828 $.ui.ddmanager.prepareOffsets(this, event);
13832 //Regenerate the absolute position used for position checks
13833 this.positionAbs = this._convertPositionTo("absolute");
13835 //Set the helper position
13836 if(!this.options.axis || this.options.axis !== "y") {
13837 this.helper[0].style.left = this.position.left+"px";
13839 if(!this.options.axis || this.options.axis !== "x") {
13840 this.helper[0].style.top = this.position.top+"px";
13844 for (i = this.items.length - 1; i >= 0; i--) {
13846 //Cache variables and intersection, continue if no intersection
13847 item = this.items[i];
13848 itemElement = item.item[0];
13849 intersection = this._intersectsWithPointer(item);
13850 if (!intersection) {
13854 // Only put the placeholder inside the current Container, skip all
13855 // items from other containers. This works because when moving
13856 // an item from one container to another the
13857 // currentContainer is switched before the placeholder is moved.
13859 // Without this, moving items in "sub-sortables" can cause
13860 // the placeholder to jitter between the outer and inner container.
13861 if (item.instance !== this.currentContainer) {
13865 // cannot intersect with itself
13866 // no useless actions that have been done before
13867 // no action if the item moved is the parent of the item checked
13868 if (itemElement !== this.currentItem[0] &&
13869 this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement &&
13870 !$.contains(this.placeholder[0], itemElement) &&
13871 (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true)
13874 this.direction = intersection === 1 ? "down" : "up";
13876 if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) {
13877 this._rearrange(event, item);
13882 this._trigger("change", event, this._uiHash());
13887 //Post events to containers
13888 this._contactContainers(event);
13890 //Interconnect with droppables
13891 if($.ui.ddmanager) {
13892 $.ui.ddmanager.drag(this, event);
13896 this._trigger("sort", event, this._uiHash());
13898 this.lastPositionAbs = this.positionAbs;
13903 _mouseStop: function(event, noPropagation) {
13909 //If we are using droppables, inform the manager about the drop
13910 if ($.ui.ddmanager && !this.options.dropBehaviour) {
13911 $.ui.ddmanager.drop(this, event);
13914 if(this.options.revert) {
13916 cur = this.placeholder.offset(),
13917 axis = this.options.axis,
13920 if ( !axis || axis === "x" ) {
13921 animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === this.document[0].body ? 0 : this.offsetParent[0].scrollLeft);
13923 if ( !axis || axis === "y" ) {
13924 animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === this.document[0].body ? 0 : this.offsetParent[0].scrollTop);
13926 this.reverting = true;
13927 $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() {
13928 that._clear(event);
13931 this._clear(event, noPropagation);
13938 cancel: function() {
13940 if(this.dragging) {
13942 this._mouseUp({ target: null });
13944 if(this.options.helper === "original") {
13945 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
13947 this.currentItem.show();
13950 //Post deactivating events to containers
13951 for (var i = this.containers.length - 1; i >= 0; i--){
13952 this.containers[i]._trigger("deactivate", null, this._uiHash(this));
13953 if(this.containers[i].containerCache.over) {
13954 this.containers[i]._trigger("out", null, this._uiHash(this));
13955 this.containers[i].containerCache.over = 0;
13961 if (this.placeholder) {
13962 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
13963 if(this.placeholder[0].parentNode) {
13964 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
13966 if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) {
13967 this.helper.remove();
13977 if(this.domPosition.prev) {
13978 $(this.domPosition.prev).after(this.currentItem);
13980 $(this.domPosition.parent).prepend(this.currentItem);
13988 serialize: function(o) {
13990 var items = this._getItemsAsjQuery(o && o.connected),
13994 $(items).each(function() {
13995 var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/));
13997 str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2]));
14001 if(!str.length && o.key) {
14002 str.push(o.key + "=");
14005 return str.join("&");
14009 toArray: function(o) {
14011 var items = this._getItemsAsjQuery(o && o.connected),
14016 items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); });
14021 /* Be careful with the following core functions */
14022 _intersectsWith: function(item) {
14024 var x1 = this.positionAbs.left,
14025 x2 = x1 + this.helperProportions.width,
14026 y1 = this.positionAbs.top,
14027 y2 = y1 + this.helperProportions.height,
14029 r = l + item.width,
14031 b = t + item.height,
14032 dyClick = this.offset.click.top,
14033 dxClick = this.offset.click.left,
14034 isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ),
14035 isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ),
14036 isOverElement = isOverElementHeight && isOverElementWidth;
14038 if ( this.options.tolerance === "pointer" ||
14039 this.options.forcePointerForContainers ||
14040 (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"])
14042 return isOverElement;
14045 return (l < x1 + (this.helperProportions.width / 2) && // Right Half
14046 x2 - (this.helperProportions.width / 2) < r && // Left Half
14047 t < y1 + (this.helperProportions.height / 2) && // Bottom Half
14048 y2 - (this.helperProportions.height / 2) < b ); // Top Half
14053 _intersectsWithPointer: function(item) {
14055 var isOverElementHeight = (this.options.axis === "x") || this._isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
14056 isOverElementWidth = (this.options.axis === "y") || this._isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
14057 isOverElement = isOverElementHeight && isOverElementWidth,
14058 verticalDirection = this._getDragVerticalDirection(),
14059 horizontalDirection = this._getDragHorizontalDirection();
14061 if (!isOverElement) {
14065 return this.floating ?
14066 ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 )
14067 : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) );
14071 _intersectsWithSides: function(item) {
14073 var isOverBottomHalf = this._isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
14074 isOverRightHalf = this._isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
14075 verticalDirection = this._getDragVerticalDirection(),
14076 horizontalDirection = this._getDragHorizontalDirection();
14078 if (this.floating && horizontalDirection) {
14079 return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf));
14081 return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf));
14086 _getDragVerticalDirection: function() {
14087 var delta = this.positionAbs.top - this.lastPositionAbs.top;
14088 return delta !== 0 && (delta > 0 ? "down" : "up");
14091 _getDragHorizontalDirection: function() {
14092 var delta = this.positionAbs.left - this.lastPositionAbs.left;
14093 return delta !== 0 && (delta > 0 ? "right" : "left");
14096 refresh: function(event) {
14097 this._refreshItems(event);
14098 this._setHandleClassName();
14099 this.refreshPositions();
14103 _connectWith: function() {
14104 var options = this.options;
14105 return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith;
14108 _getItemsAsjQuery: function(connected) {
14110 var i, j, cur, inst,
14113 connectWith = this._connectWith();
14115 if(connectWith && connected) {
14116 for (i = connectWith.length - 1; i >= 0; i--){
14117 cur = $(connectWith[i], this.document[0]);
14118 for ( j = cur.length - 1; j >= 0; j--){
14119 inst = $.data(cur[j], this.widgetFullName);
14120 if(inst && inst !== this && !inst.options.disabled) {
14121 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]);
14127 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]);
14129 function addItems() {
14130 items.push( this );
14132 for (i = queries.length - 1; i >= 0; i--){
14133 queries[i][0].each( addItems );
14140 _removeCurrentsFromItems: function() {
14142 var list = this.currentItem.find(":data(" + this.widgetName + "-item)");
14144 this.items = $.grep(this.items, function (item) {
14145 for (var j=0; j < list.length; j++) {
14146 if(list[j] === item.item[0]) {
14155 _refreshItems: function(event) {
14158 this.containers = [this];
14160 var i, j, cur, inst, targetData, _queries, item, queriesLength,
14161 items = this.items,
14162 queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]],
14163 connectWith = this._connectWith();
14165 if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down
14166 for (i = connectWith.length - 1; i >= 0; i--){
14167 cur = $(connectWith[i], this.document[0]);
14168 for (j = cur.length - 1; j >= 0; j--){
14169 inst = $.data(cur[j], this.widgetFullName);
14170 if(inst && inst !== this && !inst.options.disabled) {
14171 queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
14172 this.containers.push(inst);
14178 for (i = queries.length - 1; i >= 0; i--) {
14179 targetData = queries[i][1];
14180 _queries = queries[i][0];
14182 for (j=0, queriesLength = _queries.length; j < queriesLength; j++) {
14183 item = $(_queries[j]);
14185 item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager)
14189 instance: targetData,
14190 width: 0, height: 0,
14198 refreshPositions: function(fast) {
14200 // Determine whether items are being displayed horizontally
14201 this.floating = this.items.length ?
14202 this.options.axis === "x" || this._isFloating( this.items[ 0 ].item ) :
14205 //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
14206 if(this.offsetParent && this.helper) {
14207 this.offset.parent = this._getParentOffset();
14212 for (i = this.items.length - 1; i >= 0; i--){
14213 item = this.items[i];
14215 //We ignore calculating positions of all connected containers when we're not over them
14216 if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) {
14220 t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
14223 item.width = t.outerWidth();
14224 item.height = t.outerHeight();
14228 item.left = p.left;
14232 if(this.options.custom && this.options.custom.refreshContainers) {
14233 this.options.custom.refreshContainers.call(this);
14235 for (i = this.containers.length - 1; i >= 0; i--){
14236 p = this.containers[i].element.offset();
14237 this.containers[i].containerCache.left = p.left;
14238 this.containers[i].containerCache.top = p.top;
14239 this.containers[i].containerCache.width = this.containers[i].element.outerWidth();
14240 this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
14247 _createPlaceholder: function(that) {
14248 that = that || this;
14252 if(!o.placeholder || o.placeholder.constructor === String) {
14253 className = o.placeholder;
14255 element: function() {
14257 var nodeName = that.currentItem[0].nodeName.toLowerCase(),
14258 element = $( "<" + nodeName + ">", that.document[0] )
14259 .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder")
14260 .removeClass("ui-sortable-helper");
14262 if ( nodeName === "tbody" ) {
14263 that._createTrPlaceholder(
14264 that.currentItem.find( "tr" ).eq( 0 ),
14265 $( "<tr>", that.document[ 0 ] ).appendTo( element )
14267 } else if ( nodeName === "tr" ) {
14268 that._createTrPlaceholder( that.currentItem, element );
14269 } else if ( nodeName === "img" ) {
14270 element.attr( "src", that.currentItem.attr( "src" ) );
14273 if ( !className ) {
14274 element.css( "visibility", "hidden" );
14279 update: function(container, p) {
14281 // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that
14282 // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified
14283 if(className && !o.forcePlaceholderSize) {
14287 //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
14288 if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); }
14289 if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); }
14294 //Create the placeholder
14295 that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem));
14297 //Append it after the actual current item
14298 that.currentItem.after(that.placeholder);
14300 //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
14301 o.placeholder.update(that, that.placeholder);
14305 _createTrPlaceholder: function( sourceTr, targetTr ) {
14308 sourceTr.children().each(function() {
14309 $( "<td> </td>", that.document[ 0 ] )
14310 .attr( "colspan", $( this ).attr( "colspan" ) || 1 )
14311 .appendTo( targetTr );
14315 _contactContainers: function(event) {
14316 var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom, floating, axis,
14317 innermostContainer = null,
14318 innermostIndex = null;
14320 // get innermost container that intersects with item
14321 for (i = this.containers.length - 1; i >= 0; i--) {
14323 // never consider a container that's located within the item itself
14324 if($.contains(this.currentItem[0], this.containers[i].element[0])) {
14328 if(this._intersectsWith(this.containers[i].containerCache)) {
14330 // if we've already found a container and it's more "inner" than this, then continue
14331 if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) {
14335 innermostContainer = this.containers[i];
14336 innermostIndex = i;
14339 // container doesn't intersect. trigger "out" event if necessary
14340 if(this.containers[i].containerCache.over) {
14341 this.containers[i]._trigger("out", event, this._uiHash(this));
14342 this.containers[i].containerCache.over = 0;
14348 // if no intersecting containers found, return
14349 if(!innermostContainer) {
14353 // move the item into the container if it's not there already
14354 if(this.containers.length === 1) {
14355 if (!this.containers[innermostIndex].containerCache.over) {
14356 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
14357 this.containers[innermostIndex].containerCache.over = 1;
14361 //When entering a new container, we will find the item with the least distance and append our item near it
14363 itemWithLeastDistance = null;
14364 floating = innermostContainer.floating || this._isFloating(this.currentItem);
14365 posProperty = floating ? "left" : "top";
14366 sizeProperty = floating ? "width" : "height";
14367 axis = floating ? "clientX" : "clientY";
14369 for (j = this.items.length - 1; j >= 0; j--) {
14370 if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) {
14373 if(this.items[j].item[0] === this.currentItem[0]) {
14377 cur = this.items[j].item.offset()[posProperty];
14378 nearBottom = false;
14379 if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) {
14383 if ( Math.abs( event[ axis ] - cur ) < dist ) {
14384 dist = Math.abs( event[ axis ] - cur );
14385 itemWithLeastDistance = this.items[ j ];
14386 this.direction = nearBottom ? "up": "down";
14390 //Check if dropOnEmpty is enabled
14391 if(!itemWithLeastDistance && !this.options.dropOnEmpty) {
14395 if(this.currentContainer === this.containers[innermostIndex]) {
14396 if ( !this.currentContainer.containerCache.over ) {
14397 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() );
14398 this.currentContainer.containerCache.over = 1;
14403 itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true);
14404 this._trigger("change", event, this._uiHash());
14405 this.containers[innermostIndex]._trigger("change", event, this._uiHash(this));
14406 this.currentContainer = this.containers[innermostIndex];
14408 //Update the placeholder
14409 this.options.placeholder.update(this.currentContainer, this.placeholder);
14411 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
14412 this.containers[innermostIndex].containerCache.over = 1;
14418 _createHelper: function(event) {
14420 var o = this.options,
14421 helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem);
14423 //Add the helper to the DOM if that didn't happen already
14424 if(!helper.parents("body").length) {
14425 $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
14428 if(helper[0] === this.currentItem[0]) {
14429 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") };
14432 if(!helper[0].style.width || o.forceHelperSize) {
14433 helper.width(this.currentItem.width());
14435 if(!helper[0].style.height || o.forceHelperSize) {
14436 helper.height(this.currentItem.height());
14443 _adjustOffsetFromHelper: function(obj) {
14444 if (typeof obj === "string") {
14445 obj = obj.split(" ");
14447 if ($.isArray(obj)) {
14448 obj = {left: +obj[0], top: +obj[1] || 0};
14450 if ("left" in obj) {
14451 this.offset.click.left = obj.left + this.margins.left;
14453 if ("right" in obj) {
14454 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
14456 if ("top" in obj) {
14457 this.offset.click.top = obj.top + this.margins.top;
14459 if ("bottom" in obj) {
14460 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
14464 _getParentOffset: function() {
14467 //Get the offsetParent and cache its position
14468 this.offsetParent = this.helper.offsetParent();
14469 var po = this.offsetParent.offset();
14471 // This is a special case where we need to modify a offset calculated on start, since the following happened:
14472 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
14473 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
14474 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
14475 if(this.cssPosition === "absolute" && this.scrollParent[0] !== this.document[0] && $.contains(this.scrollParent[0], this.offsetParent[0])) {
14476 po.left += this.scrollParent.scrollLeft();
14477 po.top += this.scrollParent.scrollTop();
14480 // This needs to be actually done for all browsers, since pageX/pageY includes this information
14481 // with an ugly IE fix
14482 if( this.offsetParent[0] === this.document[0].body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
14483 po = { top: 0, left: 0 };
14487 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
14488 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
14493 _getRelativeOffset: function() {
14495 if(this.cssPosition === "relative") {
14496 var p = this.currentItem.position();
14498 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
14499 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
14502 return { top: 0, left: 0 };
14507 _cacheMargins: function() {
14509 left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
14510 top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
14514 _cacheHelperProportions: function() {
14515 this.helperProportions = {
14516 width: this.helper.outerWidth(),
14517 height: this.helper.outerHeight()
14521 _setContainment: function() {
14525 if(o.containment === "parent") {
14526 o.containment = this.helper[0].parentNode;
14528 if(o.containment === "document" || o.containment === "window") {
14529 this.containment = [
14530 0 - this.offset.relative.left - this.offset.parent.left,
14531 0 - this.offset.relative.top - this.offset.parent.top,
14532 o.containment === "document" ? this.document.width() : this.window.width() - this.helperProportions.width - this.margins.left,
14533 (o.containment === "document" ? this.document.width() : this.window.height() || this.document[0].body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
14537 if(!(/^(document|window|parent)$/).test(o.containment)) {
14538 ce = $(o.containment)[0];
14539 co = $(o.containment).offset();
14540 over = ($(ce).css("overflow") !== "hidden");
14542 this.containment = [
14543 co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
14544 co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
14545 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,
14546 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
14552 _convertPositionTo: function(d, pos) {
14555 pos = this.position;
14557 var mod = d === "absolute" ? 1 : -1,
14558 scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== this.document[0] && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent,
14559 scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
14563 pos.top + // The absolute mouse position
14564 this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
14565 this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
14566 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
14569 pos.left + // The absolute mouse position
14570 this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
14571 this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
14572 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
14578 _generatePosition: function(event) {
14582 pageX = event.pageX,
14583 pageY = event.pageY,
14584 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);
14586 // This is another very weird special case that only happens for relative elements:
14587 // 1. If the css position is relative
14588 // 2. and the scroll parent is the document or similar to the offset parent
14589 // we have to refresh the relative offset during the scroll so there are no jumps
14590 if(this.cssPosition === "relative" && !(this.scrollParent[0] !== this.document[0] && this.scrollParent[0] !== this.offsetParent[0])) {
14591 this.offset.relative = this._getRelativeOffset();
14595 * - Position constraining -
14596 * Constrain the position to a mix of grid, containment.
14599 if(this.originalPosition) { //If we are not dragging yet, we won't check for options
14601 if(this.containment) {
14602 if(event.pageX - this.offset.click.left < this.containment[0]) {
14603 pageX = this.containment[0] + this.offset.click.left;
14605 if(event.pageY - this.offset.click.top < this.containment[1]) {
14606 pageY = this.containment[1] + this.offset.click.top;
14608 if(event.pageX - this.offset.click.left > this.containment[2]) {
14609 pageX = this.containment[2] + this.offset.click.left;
14611 if(event.pageY - this.offset.click.top > this.containment[3]) {
14612 pageY = this.containment[3] + this.offset.click.top;
14617 top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
14618 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;
14620 left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
14621 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;
14628 pageY - // The absolute mouse position
14629 this.offset.click.top - // Click offset (relative to the element)
14630 this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
14631 this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
14632 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
14635 pageX - // The absolute mouse position
14636 this.offset.click.left - // Click offset (relative to the element)
14637 this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
14638 this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
14639 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
14645 _rearrange: function(event, i, a, hardRefresh) {
14647 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));
14649 //Various things done here to improve the performance:
14650 // 1. we create a setTimeout, that calls refreshPositions
14651 // 2. on the instance, we have a counter variable, that get's higher after every append
14652 // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
14653 // 4. this lets only the last addition to the timeout stack through
14654 this.counter = this.counter ? ++this.counter : 1;
14655 var counter = this.counter;
14657 this._delay(function() {
14658 if(counter === this.counter) {
14659 this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
14665 _clear: function(event, noPropagation) {
14667 this.reverting = false;
14668 // We delay all events that have to be triggered to after the point where the placeholder has been removed and
14669 // everything else normalized again
14671 delayedTriggers = [];
14673 // We first have to update the dom position of the actual currentItem
14674 // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
14675 if(!this._noFinalSort && this.currentItem.parent().length) {
14676 this.placeholder.before(this.currentItem);
14678 this._noFinalSort = null;
14680 if(this.helper[0] === this.currentItem[0]) {
14681 for(i in this._storedCSS) {
14682 if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") {
14683 this._storedCSS[i] = "";
14686 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
14688 this.currentItem.show();
14691 if(this.fromOutside && !noPropagation) {
14692 delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
14694 if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) {
14695 delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed
14698 // Check if the items Container has Changed and trigger appropriate
14700 if (this !== this.currentContainer) {
14701 if(!noPropagation) {
14702 delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); });
14703 delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
14704 delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
14709 //Post events to containers
14710 function delayEvent( type, instance, container ) {
14711 return function( event ) {
14712 container._trigger( type, event, instance._uiHash( instance ) );
14715 for (i = this.containers.length - 1; i >= 0; i--){
14716 if (!noPropagation) {
14717 delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) );
14719 if(this.containers[i].containerCache.over) {
14720 delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) );
14721 this.containers[i].containerCache.over = 0;
14725 //Do what was originally in plugins
14726 if ( this.storedCursor ) {
14727 this.document.find( "body" ).css( "cursor", this.storedCursor );
14728 this.storedStylesheet.remove();
14730 if(this._storedOpacity) {
14731 this.helper.css("opacity", this._storedOpacity);
14733 if(this._storedZIndex) {
14734 this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex);
14737 this.dragging = false;
14739 if(!noPropagation) {
14740 this._trigger("beforeStop", event, this._uiHash());
14743 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
14744 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
14746 if ( !this.cancelHelperRemoval ) {
14747 if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
14748 this.helper.remove();
14750 this.helper = null;
14753 if(!noPropagation) {
14754 for (i=0; i < delayedTriggers.length; i++) {
14755 delayedTriggers[i].call(this, event);
14756 } //Trigger all delayed events
14757 this._trigger("stop", event, this._uiHash());
14760 this.fromOutside = false;
14761 return !this.cancelHelperRemoval;
14765 _trigger: function() {
14766 if ($.Widget.prototype._trigger.apply(this, arguments) === false) {
14771 _uiHash: function(_inst) {
14772 var inst = _inst || this;
14774 helper: inst.helper,
14775 placeholder: inst.placeholder || $([]),
14776 position: inst.position,
14777 originalPosition: inst.originalPosition,
14778 offset: inst.positionAbs,
14779 item: inst.currentItem,
14780 sender: _inst ? _inst.element : null
14788 * jQuery UI Spinner 1.11.4
14789 * http://jqueryui.com
14791 * Copyright jQuery Foundation and other contributors
14792 * Released under the MIT license.
14793 * http://jquery.org/license
14795 * http://api.jqueryui.com/spinner/
14799 function spinner_modifier( fn ) {
14800 return function() {
14801 var previous = this.element.val();
14802 fn.apply( this, arguments );
14804 if ( previous !== this.element.val() ) {
14805 this._trigger( "change" );
14810 var spinner = $.widget( "ui.spinner", {
14812 defaultElement: "<input>",
14813 widgetEventPrefix: "spin",
14817 down: "ui-icon-triangle-1-s",
14818 up: "ui-icon-triangle-1-n"
14823 numberFormat: null,
14833 _create: function() {
14834 // handle string values that need to be parsed
14835 this._setOption( "max", this.options.max );
14836 this._setOption( "min", this.options.min );
14837 this._setOption( "step", this.options.step );
14839 // Only format if there is a value, prevents the field from being marked
14840 // as invalid in Firefox, see #9573.
14841 if ( this.value() !== "" ) {
14842 // Format the value, but don't constrain.
14843 this._value( this.element.val(), true );
14847 this._on( this._events );
14850 // turning off autocomplete prevents the browser from remembering the
14851 // value when navigating through history, so we re-enable autocomplete
14852 // if the page is unloaded before the widget is destroyed. #7790
14853 this._on( this.window, {
14854 beforeunload: function() {
14855 this.element.removeAttr( "autocomplete" );
14860 _getCreateOptions: function() {
14862 element = this.element;
14864 $.each( [ "min", "max", "step" ], function( i, option ) {
14865 var value = element.attr( option );
14866 if ( value !== undefined && value.length ) {
14867 options[ option ] = value;
14875 keydown: function( event ) {
14876 if ( this._start( event ) && this._keydown( event ) ) {
14877 event.preventDefault();
14881 focus: function() {
14882 this.previous = this.element.val();
14884 blur: function( event ) {
14885 if ( this.cancelBlur ) {
14886 delete this.cancelBlur;
14892 if ( this.previous !== this.element.val() ) {
14893 this._trigger( "change", event );
14896 mousewheel: function( event, delta ) {
14900 if ( !this.spinning && !this._start( event ) ) {
14904 this._spin( (delta > 0 ? 1 : -1) * this.options.step, event );
14905 clearTimeout( this.mousewheelTimer );
14906 this.mousewheelTimer = this._delay(function() {
14907 if ( this.spinning ) {
14908 this._stop( event );
14911 event.preventDefault();
14913 "mousedown .ui-spinner-button": function( event ) {
14916 // We never want the buttons to have focus; whenever the user is
14917 // interacting with the spinner, the focus should be on the input.
14918 // If the input is focused then this.previous is properly set from
14919 // when the input first received focus. If the input is not focused
14920 // then we need to set this.previous based on the value before spinning.
14921 previous = this.element[0] === this.document[0].activeElement ?
14922 this.previous : this.element.val();
14923 function checkFocus() {
14924 var isActive = this.element[0] === this.document[0].activeElement;
14926 this.element.focus();
14927 this.previous = previous;
14929 // IE sets focus asynchronously, so we need to check if focus
14930 // moved off of the input because the user clicked on the button.
14931 this._delay(function() {
14932 this.previous = previous;
14937 // ensure focus is on (or stays on) the text field
14938 event.preventDefault();
14939 checkFocus.call( this );
14942 // IE doesn't prevent moving focus even with event.preventDefault()
14943 // so we set a flag to know when we should ignore the blur event
14944 // and check (again) if focus moved off of the input.
14945 this.cancelBlur = true;
14946 this._delay(function() {
14947 delete this.cancelBlur;
14948 checkFocus.call( this );
14951 if ( this._start( event ) === false ) {
14955 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
14957 "mouseup .ui-spinner-button": "_stop",
14958 "mouseenter .ui-spinner-button": function( event ) {
14959 // button will add ui-state-active if mouse was down while mouseleave and kept down
14960 if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
14964 if ( this._start( event ) === false ) {
14967 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
14969 // TODO: do we really want to consider this a stop?
14970 // shouldn't we just stop the repeater and wait until mouseup before
14971 // we trigger the stop event?
14972 "mouseleave .ui-spinner-button": "_stop"
14975 _draw: function() {
14976 var uiSpinner = this.uiSpinner = this.element
14977 .addClass( "ui-spinner-input" )
14978 .attr( "autocomplete", "off" )
14979 .wrap( this._uiSpinnerHtml() )
14982 .append( this._buttonHtml() );
14984 this.element.attr( "role", "spinbutton" );
14987 this.buttons = uiSpinner.find( ".ui-spinner-button" )
14988 .attr( "tabIndex", -1 )
14990 .removeClass( "ui-corner-all" );
14992 // IE 6 doesn't understand height: 50% for the buttons
14993 // unless the wrapper has an explicit height
14994 if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) &&
14995 uiSpinner.height() > 0 ) {
14996 uiSpinner.height( uiSpinner.height() );
14999 // disable spinner if element was already disabled
15000 if ( this.options.disabled ) {
15005 _keydown: function( event ) {
15006 var options = this.options,
15007 keyCode = $.ui.keyCode;
15009 switch ( event.keyCode ) {
15011 this._repeat( null, 1, event );
15014 this._repeat( null, -1, event );
15016 case keyCode.PAGE_UP:
15017 this._repeat( null, options.page, event );
15019 case keyCode.PAGE_DOWN:
15020 this._repeat( null, -options.page, event );
15027 _uiSpinnerHtml: function() {
15028 return "<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>";
15031 _buttonHtml: function() {
15033 "<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>" +
15034 "<span class='ui-icon " + this.options.icons.up + "'>▲</span>" +
15036 "<a class='ui-spinner-button ui-spinner-down ui-corner-br'>" +
15037 "<span class='ui-icon " + this.options.icons.down + "'>▼</span>" +
15041 _start: function( event ) {
15042 if ( !this.spinning && this._trigger( "start", event ) === false ) {
15046 if ( !this.counter ) {
15049 this.spinning = true;
15053 _repeat: function( i, steps, event ) {
15056 clearTimeout( this.timer );
15057 this.timer = this._delay(function() {
15058 this._repeat( 40, steps, event );
15061 this._spin( steps * this.options.step, event );
15064 _spin: function( step, event ) {
15065 var value = this.value() || 0;
15067 if ( !this.counter ) {
15071 value = this._adjustValue( value + step * this._increment( this.counter ) );
15073 if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) {
15074 this._value( value );
15079 _increment: function( i ) {
15080 var incremental = this.options.incremental;
15082 if ( incremental ) {
15083 return $.isFunction( incremental ) ?
15085 Math.floor( i * i * i / 50000 - i * i / 500 + 17 * i / 200 + 1 );
15091 _precision: function() {
15092 var precision = this._precisionOf( this.options.step );
15093 if ( this.options.min !== null ) {
15094 precision = Math.max( precision, this._precisionOf( this.options.min ) );
15099 _precisionOf: function( num ) {
15100 var str = num.toString(),
15101 decimal = str.indexOf( "." );
15102 return decimal === -1 ? 0 : str.length - decimal - 1;
15105 _adjustValue: function( value ) {
15106 var base, aboveMin,
15107 options = this.options;
15109 // make sure we're at a valid step
15110 // - find out where we are relative to the base (min or 0)
15111 base = options.min !== null ? options.min : 0;
15112 aboveMin = value - base;
15113 // - round to the nearest step
15114 aboveMin = Math.round(aboveMin / options.step) * options.step;
15115 // - rounding is based on 0, so adjust back to our base
15116 value = base + aboveMin;
15118 // fix precision from bad JS floating point math
15119 value = parseFloat( value.toFixed( this._precision() ) );
15122 if ( options.max !== null && value > options.max) {
15123 return options.max;
15125 if ( options.min !== null && value < options.min ) {
15126 return options.min;
15132 _stop: function( event ) {
15133 if ( !this.spinning ) {
15137 clearTimeout( this.timer );
15138 clearTimeout( this.mousewheelTimer );
15140 this.spinning = false;
15141 this._trigger( "stop", event );
15144 _setOption: function( key, value ) {
15145 if ( key === "culture" || key === "numberFormat" ) {
15146 var prevValue = this._parse( this.element.val() );
15147 this.options[ key ] = value;
15148 this.element.val( this._format( prevValue ) );
15152 if ( key === "max" || key === "min" || key === "step" ) {
15153 if ( typeof value === "string" ) {
15154 value = this._parse( value );
15157 if ( key === "icons" ) {
15158 this.buttons.first().find( ".ui-icon" )
15159 .removeClass( this.options.icons.up )
15160 .addClass( value.up );
15161 this.buttons.last().find( ".ui-icon" )
15162 .removeClass( this.options.icons.down )
15163 .addClass( value.down );
15166 this._super( key, value );
15168 if ( key === "disabled" ) {
15169 this.widget().toggleClass( "ui-state-disabled", !!value );
15170 this.element.prop( "disabled", !!value );
15171 this.buttons.button( value ? "disable" : "enable" );
15175 _setOptions: spinner_modifier(function( options ) {
15176 this._super( options );
15179 _parse: function( val ) {
15180 if ( typeof val === "string" && val !== "" ) {
15181 val = window.Globalize && this.options.numberFormat ?
15182 Globalize.parseFloat( val, 10, this.options.culture ) : +val;
15184 return val === "" || isNaN( val ) ? null : val;
15187 _format: function( value ) {
15188 if ( value === "" ) {
15191 return window.Globalize && this.options.numberFormat ?
15192 Globalize.format( value, this.options.numberFormat, this.options.culture ) :
15196 _refresh: function() {
15197 this.element.attr({
15198 "aria-valuemin": this.options.min,
15199 "aria-valuemax": this.options.max,
15200 // TODO: what should we do with values that can't be parsed?
15201 "aria-valuenow": this._parse( this.element.val() )
15205 isValid: function() {
15206 var value = this.value();
15209 if ( value === null ) {
15213 // if value gets adjusted, it's invalid
15214 return value === this._adjustValue( value );
15217 // update the value without triggering change
15218 _value: function( value, allowAny ) {
15220 if ( value !== "" ) {
15221 parsed = this._parse( value );
15222 if ( parsed !== null ) {
15224 parsed = this._adjustValue( parsed );
15226 value = this._format( parsed );
15229 this.element.val( value );
15233 _destroy: function() {
15235 .removeClass( "ui-spinner-input" )
15236 .prop( "disabled", false )
15237 .removeAttr( "autocomplete" )
15238 .removeAttr( "role" )
15239 .removeAttr( "aria-valuemin" )
15240 .removeAttr( "aria-valuemax" )
15241 .removeAttr( "aria-valuenow" );
15242 this.uiSpinner.replaceWith( this.element );
15245 stepUp: spinner_modifier(function( steps ) {
15246 this._stepUp( steps );
15248 _stepUp: function( steps ) {
15249 if ( this._start() ) {
15250 this._spin( (steps || 1) * this.options.step );
15255 stepDown: spinner_modifier(function( steps ) {
15256 this._stepDown( steps );
15258 _stepDown: function( steps ) {
15259 if ( this._start() ) {
15260 this._spin( (steps || 1) * -this.options.step );
15265 pageUp: spinner_modifier(function( pages ) {
15266 this._stepUp( (pages || 1) * this.options.page );
15269 pageDown: spinner_modifier(function( pages ) {
15270 this._stepDown( (pages || 1) * this.options.page );
15273 value: function( newVal ) {
15274 if ( !arguments.length ) {
15275 return this._parse( this.element.val() );
15277 spinner_modifier( this._value ).call( this, newVal );
15280 widget: function() {
15281 return this.uiSpinner;
15287 * jQuery UI Tabs 1.11.4
15288 * http://jqueryui.com
15290 * Copyright jQuery Foundation and other contributors
15291 * Released under the MIT license.
15292 * http://jquery.org/license
15294 * http://api.jqueryui.com/tabs/
15298 var tabs = $.widget( "ui.tabs", {
15303 collapsible: false,
15305 heightStyle: "content",
15311 beforeActivate: null,
15316 _isLocal: (function() {
15317 var rhash = /#.*$/;
15319 return function( anchor ) {
15320 var anchorUrl, locationUrl;
15323 // IE7 doesn't normalize the href property when set via script (#9317)
15324 anchor = anchor.cloneNode( false );
15326 anchorUrl = anchor.href.replace( rhash, "" );
15327 locationUrl = location.href.replace( rhash, "" );
15329 // decoding may throw an error if the URL isn't UTF-8 (#9518)
15331 anchorUrl = decodeURIComponent( anchorUrl );
15332 } catch ( error ) {}
15334 locationUrl = decodeURIComponent( locationUrl );
15335 } catch ( error ) {}
15337 return anchor.hash.length > 1 && anchorUrl === locationUrl;
15341 _create: function() {
15343 options = this.options;
15345 this.running = false;
15348 .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" )
15349 .toggleClass( "ui-tabs-collapsible", options.collapsible );
15351 this._processTabs();
15352 options.active = this._initialActive();
15354 // Take disabling tabs via class attribute from HTML
15355 // into account and update option properly.
15356 if ( $.isArray( options.disabled ) ) {
15357 options.disabled = $.unique( options.disabled.concat(
15358 $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
15359 return that.tabs.index( li );
15364 // check for length avoids error when initializing empty list
15365 if ( this.options.active !== false && this.anchors.length ) {
15366 this.active = this._findActive( options.active );
15373 if ( this.active.length ) {
15374 this.load( options.active );
15378 _initialActive: function() {
15379 var active = this.options.active,
15380 collapsible = this.options.collapsible,
15381 locationHash = location.hash.substring( 1 );
15383 if ( active === null ) {
15384 // check the fragment identifier in the URL
15385 if ( locationHash ) {
15386 this.tabs.each(function( i, tab ) {
15387 if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
15394 // check for a tab marked active via a class
15395 if ( active === null ) {
15396 active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
15399 // no active tab, set to false
15400 if ( active === null || active === -1 ) {
15401 active = this.tabs.length ? 0 : false;
15405 // handle numbers: negative, out of range
15406 if ( active !== false ) {
15407 active = this.tabs.index( this.tabs.eq( active ) );
15408 if ( active === -1 ) {
15409 active = collapsible ? false : 0;
15413 // don't allow collapsible: false and active: false
15414 if ( !collapsible && active === false && this.anchors.length ) {
15421 _getCreateEventData: function() {
15424 panel: !this.active.length ? $() : this._getPanelForTab( this.active )
15428 _tabKeydown: function( event ) {
15429 var focusedTab = $( this.document[0].activeElement ).closest( "li" ),
15430 selectedIndex = this.tabs.index( focusedTab ),
15431 goingForward = true;
15433 if ( this._handlePageNav( event ) ) {
15437 switch ( event.keyCode ) {
15438 case $.ui.keyCode.RIGHT:
15439 case $.ui.keyCode.DOWN:
15442 case $.ui.keyCode.UP:
15443 case $.ui.keyCode.LEFT:
15444 goingForward = false;
15447 case $.ui.keyCode.END:
15448 selectedIndex = this.anchors.length - 1;
15450 case $.ui.keyCode.HOME:
15453 case $.ui.keyCode.SPACE:
15454 // Activate only, no collapsing
15455 event.preventDefault();
15456 clearTimeout( this.activating );
15457 this._activate( selectedIndex );
15459 case $.ui.keyCode.ENTER:
15460 // Toggle (cancel delayed activation, allow collapsing)
15461 event.preventDefault();
15462 clearTimeout( this.activating );
15463 // Determine if we should collapse or activate
15464 this._activate( selectedIndex === this.options.active ? false : selectedIndex );
15470 // Focus the appropriate tab, based on which key was pressed
15471 event.preventDefault();
15472 clearTimeout( this.activating );
15473 selectedIndex = this._focusNextTab( selectedIndex, goingForward );
15475 // Navigating with control/command key will prevent automatic activation
15476 if ( !event.ctrlKey && !event.metaKey ) {
15478 // Update aria-selected immediately so that AT think the tab is already selected.
15479 // Otherwise AT may confuse the user by stating that they need to activate the tab,
15480 // but the tab will already be activated by the time the announcement finishes.
15481 focusedTab.attr( "aria-selected", "false" );
15482 this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
15484 this.activating = this._delay(function() {
15485 this.option( "active", selectedIndex );
15490 _panelKeydown: function( event ) {
15491 if ( this._handlePageNav( event ) ) {
15495 // Ctrl+up moves focus to the current tab
15496 if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
15497 event.preventDefault();
15498 this.active.focus();
15502 // Alt+page up/down moves focus to the previous/next tab (and activates)
15503 _handlePageNav: function( event ) {
15504 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
15505 this._activate( this._focusNextTab( this.options.active - 1, false ) );
15508 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
15509 this._activate( this._focusNextTab( this.options.active + 1, true ) );
15514 _findNextTab: function( index, goingForward ) {
15515 var lastTabIndex = this.tabs.length - 1;
15517 function constrain() {
15518 if ( index > lastTabIndex ) {
15522 index = lastTabIndex;
15527 while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
15528 index = goingForward ? index + 1 : index - 1;
15534 _focusNextTab: function( index, goingForward ) {
15535 index = this._findNextTab( index, goingForward );
15536 this.tabs.eq( index ).focus();
15540 _setOption: function( key, value ) {
15541 if ( key === "active" ) {
15542 // _activate() will handle invalid values and update this.options
15543 this._activate( value );
15547 if ( key === "disabled" ) {
15548 // don't use the widget factory's disabled handling
15549 this._setupDisabled( value );
15553 this._super( key, value);
15555 if ( key === "collapsible" ) {
15556 this.element.toggleClass( "ui-tabs-collapsible", value );
15557 // Setting collapsible: false while collapsed; open first panel
15558 if ( !value && this.options.active === false ) {
15559 this._activate( 0 );
15563 if ( key === "event" ) {
15564 this._setupEvents( value );
15567 if ( key === "heightStyle" ) {
15568 this._setupHeightStyle( value );
15572 _sanitizeSelector: function( hash ) {
15573 return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
15576 refresh: function() {
15577 var options = this.options,
15578 lis = this.tablist.children( ":has(a[href])" );
15580 // get disabled tabs from class attribute from HTML
15581 // this will get converted to a boolean if needed in _refresh()
15582 options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
15583 return lis.index( tab );
15586 this._processTabs();
15588 // was collapsed or no tabs
15589 if ( options.active === false || !this.anchors.length ) {
15590 options.active = false;
15592 // was active, but active tab is gone
15593 } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
15594 // all remaining tabs are disabled
15595 if ( this.tabs.length === options.disabled.length ) {
15596 options.active = false;
15598 // activate previous tab
15600 this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
15602 // was active, active tab still exists
15604 // make sure active index is correct
15605 options.active = this.tabs.index( this.active );
15611 _refresh: function() {
15612 this._setupDisabled( this.options.disabled );
15613 this._setupEvents( this.options.event );
15614 this._setupHeightStyle( this.options.heightStyle );
15616 this.tabs.not( this.active ).attr({
15617 "aria-selected": "false",
15618 "aria-expanded": "false",
15621 this.panels.not( this._getPanelForTab( this.active ) )
15624 "aria-hidden": "true"
15627 // Make sure one tab is in the tab order
15628 if ( !this.active.length ) {
15629 this.tabs.eq( 0 ).attr( "tabIndex", 0 );
15632 .addClass( "ui-tabs-active ui-state-active" )
15634 "aria-selected": "true",
15635 "aria-expanded": "true",
15638 this._getPanelForTab( this.active )
15641 "aria-hidden": "false"
15646 _processTabs: function() {
15648 prevTabs = this.tabs,
15649 prevAnchors = this.anchors,
15650 prevPanels = this.panels;
15652 this.tablist = this._getList()
15653 .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
15654 .attr( "role", "tablist" )
15656 // Prevent users from focusing disabled tabs via click
15657 .delegate( "> li", "mousedown" + this.eventNamespace, function( event ) {
15658 if ( $( this ).is( ".ui-state-disabled" ) ) {
15659 event.preventDefault();
15664 // Preventing the default action in mousedown doesn't prevent IE
15665 // from focusing the element, so if the anchor gets focused, blur.
15666 // We don't have to worry about focusing the previously focused
15667 // element since clicking on a non-focusable element should focus
15668 // the body anyway.
15669 .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() {
15670 if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
15675 this.tabs = this.tablist.find( "> li:has(a[href])" )
15676 .addClass( "ui-state-default ui-corner-top" )
15682 this.anchors = this.tabs.map(function() {
15683 return $( "a", this )[ 0 ];
15685 .addClass( "ui-tabs-anchor" )
15687 role: "presentation",
15693 this.anchors.each(function( i, anchor ) {
15694 var selector, panel, panelId,
15695 anchorId = $( anchor ).uniqueId().attr( "id" ),
15696 tab = $( anchor ).closest( "li" ),
15697 originalAriaControls = tab.attr( "aria-controls" );
15700 if ( that._isLocal( anchor ) ) {
15701 selector = anchor.hash;
15702 panelId = selector.substring( 1 );
15703 panel = that.element.find( that._sanitizeSelector( selector ) );
15706 // If the tab doesn't already have aria-controls,
15707 // generate an id by using a throw-away element
15708 panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id;
15709 selector = "#" + panelId;
15710 panel = that.element.find( selector );
15711 if ( !panel.length ) {
15712 panel = that._createPanel( panelId );
15713 panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
15715 panel.attr( "aria-live", "polite" );
15718 if ( panel.length) {
15719 that.panels = that.panels.add( panel );
15721 if ( originalAriaControls ) {
15722 tab.data( "ui-tabs-aria-controls", originalAriaControls );
15725 "aria-controls": panelId,
15726 "aria-labelledby": anchorId
15728 panel.attr( "aria-labelledby", anchorId );
15732 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
15733 .attr( "role", "tabpanel" );
15735 // Avoid memory leaks (#10056)
15737 this._off( prevTabs.not( this.tabs ) );
15738 this._off( prevAnchors.not( this.anchors ) );
15739 this._off( prevPanels.not( this.panels ) );
15743 // allow overriding how to find the list for rare usage scenarios (#7715)
15744 _getList: function() {
15745 return this.tablist || this.element.find( "ol,ul" ).eq( 0 );
15748 _createPanel: function( id ) {
15749 return $( "<div>" )
15751 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
15752 .data( "ui-tabs-destroy", true );
15755 _setupDisabled: function( disabled ) {
15756 if ( $.isArray( disabled ) ) {
15757 if ( !disabled.length ) {
15759 } else if ( disabled.length === this.anchors.length ) {
15765 for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) {
15766 if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
15768 .addClass( "ui-state-disabled" )
15769 .attr( "aria-disabled", "true" );
15772 .removeClass( "ui-state-disabled" )
15773 .removeAttr( "aria-disabled" );
15777 this.options.disabled = disabled;
15780 _setupEvents: function( event ) {
15783 $.each( event.split(" "), function( index, eventName ) {
15784 events[ eventName ] = "_eventHandler";
15788 this._off( this.anchors.add( this.tabs ).add( this.panels ) );
15789 // Always prevent the default action, even when disabled
15790 this._on( true, this.anchors, {
15791 click: function( event ) {
15792 event.preventDefault();
15795 this._on( this.anchors, events );
15796 this._on( this.tabs, { keydown: "_tabKeydown" } );
15797 this._on( this.panels, { keydown: "_panelKeydown" } );
15799 this._focusable( this.tabs );
15800 this._hoverable( this.tabs );
15803 _setupHeightStyle: function( heightStyle ) {
15805 parent = this.element.parent();
15807 if ( heightStyle === "fill" ) {
15808 maxHeight = parent.height();
15809 maxHeight -= this.element.outerHeight() - this.element.height();
15811 this.element.siblings( ":visible" ).each(function() {
15812 var elem = $( this ),
15813 position = elem.css( "position" );
15815 if ( position === "absolute" || position === "fixed" ) {
15818 maxHeight -= elem.outerHeight( true );
15821 this.element.children().not( this.panels ).each(function() {
15822 maxHeight -= $( this ).outerHeight( true );
15825 this.panels.each(function() {
15826 $( this ).height( Math.max( 0, maxHeight -
15827 $( this ).innerHeight() + $( this ).height() ) );
15829 .css( "overflow", "auto" );
15830 } else if ( heightStyle === "auto" ) {
15832 this.panels.each(function() {
15833 maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
15834 }).height( maxHeight );
15838 _eventHandler: function( event ) {
15839 var options = this.options,
15840 active = this.active,
15841 anchor = $( event.currentTarget ),
15842 tab = anchor.closest( "li" ),
15843 clickedIsActive = tab[ 0 ] === active[ 0 ],
15844 collapsing = clickedIsActive && options.collapsible,
15845 toShow = collapsing ? $() : this._getPanelForTab( tab ),
15846 toHide = !active.length ? $() : this._getPanelForTab( active ),
15850 newTab: collapsing ? $() : tab,
15854 event.preventDefault();
15856 if ( tab.hasClass( "ui-state-disabled" ) ||
15857 // tab is already loading
15858 tab.hasClass( "ui-tabs-loading" ) ||
15859 // can't switch durning an animation
15861 // click on active header, but not collapsible
15862 ( clickedIsActive && !options.collapsible ) ||
15863 // allow canceling activation
15864 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
15868 options.active = collapsing ? false : this.tabs.index( tab );
15870 this.active = clickedIsActive ? $() : tab;
15875 if ( !toHide.length && !toShow.length ) {
15876 $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
15879 if ( toShow.length ) {
15880 this.load( this.tabs.index( tab ), event );
15882 this._toggle( event, eventData );
15885 // handles show/hide for selecting tabs
15886 _toggle: function( event, eventData ) {
15888 toShow = eventData.newPanel,
15889 toHide = eventData.oldPanel;
15891 this.running = true;
15893 function complete() {
15894 that.running = false;
15895 that._trigger( "activate", event, eventData );
15899 eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" );
15901 if ( toShow.length && that.options.show ) {
15902 that._show( toShow, that.options.show, complete );
15909 // start out by hiding, then showing, then completing
15910 if ( toHide.length && this.options.hide ) {
15911 this._hide( toHide, this.options.hide, function() {
15912 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
15916 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
15921 toHide.attr( "aria-hidden", "true" );
15922 eventData.oldTab.attr({
15923 "aria-selected": "false",
15924 "aria-expanded": "false"
15926 // If we're switching tabs, remove the old tab from the tab order.
15927 // If we're opening from collapsed state, remove the previous tab from the tab order.
15928 // If we're collapsing, then keep the collapsing tab in the tab order.
15929 if ( toShow.length && toHide.length ) {
15930 eventData.oldTab.attr( "tabIndex", -1 );
15931 } else if ( toShow.length ) {
15932 this.tabs.filter(function() {
15933 return $( this ).attr( "tabIndex" ) === 0;
15935 .attr( "tabIndex", -1 );
15938 toShow.attr( "aria-hidden", "false" );
15939 eventData.newTab.attr({
15940 "aria-selected": "true",
15941 "aria-expanded": "true",
15946 _activate: function( index ) {
15948 active = this._findActive( index );
15950 // trying to activate the already active panel
15951 if ( active[ 0 ] === this.active[ 0 ] ) {
15955 // trying to collapse, simulate a click on the current active header
15956 if ( !active.length ) {
15957 active = this.active;
15960 anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
15961 this._eventHandler({
15963 currentTarget: anchor,
15964 preventDefault: $.noop
15968 _findActive: function( index ) {
15969 return index === false ? $() : this.tabs.eq( index );
15972 _getIndex: function( index ) {
15973 // meta-function to give users option to provide a href string instead of a numerical index.
15974 if ( typeof index === "string" ) {
15975 index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) );
15981 _destroy: function() {
15986 this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" );
15989 .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
15990 .removeAttr( "role" );
15993 .removeClass( "ui-tabs-anchor" )
15994 .removeAttr( "role" )
15995 .removeAttr( "tabIndex" )
15998 this.tablist.unbind( this.eventNamespace );
16000 this.tabs.add( this.panels ).each(function() {
16001 if ( $.data( this, "ui-tabs-destroy" ) ) {
16002 $( this ).remove();
16005 .removeClass( "ui-state-default ui-state-active ui-state-disabled " +
16006 "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" )
16007 .removeAttr( "tabIndex" )
16008 .removeAttr( "aria-live" )
16009 .removeAttr( "aria-busy" )
16010 .removeAttr( "aria-selected" )
16011 .removeAttr( "aria-labelledby" )
16012 .removeAttr( "aria-hidden" )
16013 .removeAttr( "aria-expanded" )
16014 .removeAttr( "role" );
16018 this.tabs.each(function() {
16019 var li = $( this ),
16020 prev = li.data( "ui-tabs-aria-controls" );
16023 .attr( "aria-controls", prev )
16024 .removeData( "ui-tabs-aria-controls" );
16026 li.removeAttr( "aria-controls" );
16030 this.panels.show();
16032 if ( this.options.heightStyle !== "content" ) {
16033 this.panels.css( "height", "" );
16037 enable: function( index ) {
16038 var disabled = this.options.disabled;
16039 if ( disabled === false ) {
16043 if ( index === undefined ) {
16046 index = this._getIndex( index );
16047 if ( $.isArray( disabled ) ) {
16048 disabled = $.map( disabled, function( num ) {
16049 return num !== index ? num : null;
16052 disabled = $.map( this.tabs, function( li, num ) {
16053 return num !== index ? num : null;
16057 this._setupDisabled( disabled );
16060 disable: function( index ) {
16061 var disabled = this.options.disabled;
16062 if ( disabled === true ) {
16066 if ( index === undefined ) {
16069 index = this._getIndex( index );
16070 if ( $.inArray( index, disabled ) !== -1 ) {
16073 if ( $.isArray( disabled ) ) {
16074 disabled = $.merge( [ index ], disabled ).sort();
16076 disabled = [ index ];
16079 this._setupDisabled( disabled );
16082 load: function( index, event ) {
16083 index = this._getIndex( index );
16085 tab = this.tabs.eq( index ),
16086 anchor = tab.find( ".ui-tabs-anchor" ),
16087 panel = this._getPanelForTab( tab ),
16092 complete = function( jqXHR, status ) {
16093 if ( status === "abort" ) {
16094 that.panels.stop( false, true );
16097 tab.removeClass( "ui-tabs-loading" );
16098 panel.removeAttr( "aria-busy" );
16100 if ( jqXHR === that.xhr ) {
16106 if ( this._isLocal( anchor[ 0 ] ) ) {
16110 this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
16112 // support: jQuery <1.8
16113 // jQuery <1.8 returns false if the request is canceled in beforeSend,
16114 // but as of 1.8, $.ajax() always returns a jqXHR object.
16115 if ( this.xhr && this.xhr.statusText !== "canceled" ) {
16116 tab.addClass( "ui-tabs-loading" );
16117 panel.attr( "aria-busy", "true" );
16120 .done(function( response, status, jqXHR ) {
16121 // support: jQuery <1.8
16122 // http://bugs.jquery.com/ticket/11778
16123 setTimeout(function() {
16124 panel.html( response );
16125 that._trigger( "load", event, eventData );
16127 complete( jqXHR, status );
16130 .fail(function( jqXHR, status ) {
16131 // support: jQuery <1.8
16132 // http://bugs.jquery.com/ticket/11778
16133 setTimeout(function() {
16134 complete( jqXHR, status );
16140 _ajaxSettings: function( anchor, event, eventData ) {
16143 url: anchor.attr( "href" ),
16144 beforeSend: function( jqXHR, settings ) {
16145 return that._trigger( "beforeLoad", event,
16146 $.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) );
16151 _getPanelForTab: function( tab ) {
16152 var id = $( tab ).attr( "aria-controls" );
16153 return this.element.find( this._sanitizeSelector( "#" + id ) );
16159 * jQuery UI Tooltip 1.11.4
16160 * http://jqueryui.com
16162 * Copyright jQuery Foundation and other contributors
16163 * Released under the MIT license.
16164 * http://jquery.org/license
16166 * http://api.jqueryui.com/tooltip/
16170 var tooltip = $.widget( "ui.tooltip", {
16173 content: function() {
16174 // support: IE<9, Opera in jQuery <1.7
16175 // .text() can't accept undefined, so coerce to a string
16176 var title = $( this ).attr( "title" ) || "";
16177 // Escape title, since we're going from an attribute to raw HTML
16178 return $( "<a>" ).text( title ).html();
16181 // Disabled elements have inconsistent behavior across browsers (#8661)
16182 items: "[title]:not([disabled])",
16186 collision: "flipfit flip"
16189 tooltipClass: null,
16197 _addDescribedBy: function( elem, id ) {
16198 var describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ );
16199 describedby.push( id );
16201 .data( "ui-tooltip-id", id )
16202 .attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
16205 _removeDescribedBy: function( elem ) {
16206 var id = elem.data( "ui-tooltip-id" ),
16207 describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ),
16208 index = $.inArray( id, describedby );
16210 if ( index !== -1 ) {
16211 describedby.splice( index, 1 );
16214 elem.removeData( "ui-tooltip-id" );
16215 describedby = $.trim( describedby.join( " " ) );
16216 if ( describedby ) {
16217 elem.attr( "aria-describedby", describedby );
16219 elem.removeAttr( "aria-describedby" );
16223 _create: function() {
16229 // IDs of generated tooltips, needed for destroy
16230 this.tooltips = {};
16232 // IDs of parent tooltips where we removed the title attribute
16235 if ( this.options.disabled ) {
16239 // Append the aria-live region so tooltips announce correctly
16240 this.liveRegion = $( "<div>" )
16243 "aria-live": "assertive",
16244 "aria-relevant": "additions"
16246 .addClass( "ui-helper-hidden-accessible" )
16247 .appendTo( this.document[ 0 ].body );
16250 _setOption: function( key, value ) {
16253 if ( key === "disabled" ) {
16254 this[ value ? "_disable" : "_enable" ]();
16255 this.options[ key ] = value;
16256 // disable element style changes
16260 this._super( key, value );
16262 if ( key === "content" ) {
16263 $.each( this.tooltips, function( id, tooltipData ) {
16264 that._updateContent( tooltipData.element );
16269 _disable: function() {
16272 // close open tooltips
16273 $.each( this.tooltips, function( id, tooltipData ) {
16274 var event = $.Event( "blur" );
16275 event.target = event.currentTarget = tooltipData.element[ 0 ];
16276 that.close( event, true );
16279 // remove title attributes to prevent native tooltips
16280 this.element.find( this.options.items ).addBack().each(function() {
16281 var element = $( this );
16282 if ( element.is( "[title]" ) ) {
16284 .data( "ui-tooltip-title", element.attr( "title" ) )
16285 .removeAttr( "title" );
16290 _enable: function() {
16291 // restore title attributes
16292 this.element.find( this.options.items ).addBack().each(function() {
16293 var element = $( this );
16294 if ( element.data( "ui-tooltip-title" ) ) {
16295 element.attr( "title", element.data( "ui-tooltip-title" ) );
16300 open: function( event ) {
16302 target = $( event ? event.target : this.element )
16303 // we need closest here due to mouseover bubbling,
16304 // but always pointing at the same event target
16305 .closest( this.options.items );
16307 // No element to show a tooltip for or the tooltip is already open
16308 if ( !target.length || target.data( "ui-tooltip-id" ) ) {
16312 if ( target.attr( "title" ) ) {
16313 target.data( "ui-tooltip-title", target.attr( "title" ) );
16316 target.data( "ui-tooltip-open", true );
16318 // kill parent tooltips, custom or native, for hover
16319 if ( event && event.type === "mouseover" ) {
16320 target.parents().each(function() {
16321 var parent = $( this ),
16323 if ( parent.data( "ui-tooltip-open" ) ) {
16324 blurEvent = $.Event( "blur" );
16325 blurEvent.target = blurEvent.currentTarget = this;
16326 that.close( blurEvent, true );
16328 if ( parent.attr( "title" ) ) {
16330 that.parents[ this.id ] = {
16332 title: parent.attr( "title" )
16334 parent.attr( "title", "" );
16339 this._registerCloseHandlers( event, target );
16340 this._updateContent( target, event );
16343 _updateContent: function( target, event ) {
16345 contentOption = this.options.content,
16347 eventType = event ? event.type : null;
16349 if ( typeof contentOption === "string" ) {
16350 return this._open( event, target, contentOption );
16353 content = contentOption.call( target[0], function( response ) {
16355 // IE may instantly serve a cached response for ajax requests
16356 // delay this call to _open so the other call to _open runs first
16357 that._delay(function() {
16359 // Ignore async response if tooltip was closed already
16360 if ( !target.data( "ui-tooltip-open" ) ) {
16364 // jQuery creates a special event for focusin when it doesn't
16365 // exist natively. To improve performance, the native event
16366 // object is reused and the type is changed. Therefore, we can't
16367 // rely on the type being correct after the event finished
16368 // bubbling, so we set it back to the previous value. (#8740)
16370 event.type = eventType;
16372 this._open( event, target, response );
16376 this._open( event, target, content );
16380 _open: function( event, target, content ) {
16381 var tooltipData, tooltip, delayedShow, a11yContent,
16382 positionOption = $.extend( {}, this.options.position );
16388 // Content can be updated multiple times. If the tooltip already
16389 // exists, then just update the content and bail.
16390 tooltipData = this._find( target );
16391 if ( tooltipData ) {
16392 tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content );
16396 // if we have a title, clear it to prevent the native tooltip
16397 // we have to check first to avoid defining a title if none exists
16398 // (we don't want to cause an element to start matching [title])
16400 // We use removeAttr only for key events, to allow IE to export the correct
16401 // accessible attributes. For mouse events, set to empty string to avoid
16402 // native tooltip showing up (happens only when removing inside mouseover).
16403 if ( target.is( "[title]" ) ) {
16404 if ( event && event.type === "mouseover" ) {
16405 target.attr( "title", "" );
16407 target.removeAttr( "title" );
16411 tooltipData = this._tooltip( target );
16412 tooltip = tooltipData.tooltip;
16413 this._addDescribedBy( target, tooltip.attr( "id" ) );
16414 tooltip.find( ".ui-tooltip-content" ).html( content );
16416 // Support: Voiceover on OS X, JAWS on IE <= 9
16417 // JAWS announces deletions even when aria-relevant="additions"
16418 // Voiceover will sometimes re-read the entire log region's contents from the beginning
16419 this.liveRegion.children().hide();
16420 if ( content.clone ) {
16421 a11yContent = content.clone();
16422 a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" );
16424 a11yContent = content;
16426 $( "<div>" ).html( a11yContent ).appendTo( this.liveRegion );
16428 function position( event ) {
16429 positionOption.of = event;
16430 if ( tooltip.is( ":hidden" ) ) {
16433 tooltip.position( positionOption );
16435 if ( this.options.track && event && /^mouse/.test( event.type ) ) {
16436 this._on( this.document, {
16437 mousemove: position
16439 // trigger once to override element-relative positioning
16442 tooltip.position( $.extend({
16444 }, this.options.position ) );
16449 this._show( tooltip, this.options.show );
16450 // Handle tracking tooltips that are shown with a delay (#8644). As soon
16451 // as the tooltip is visible, position the tooltip using the most recent
16453 if ( this.options.show && this.options.show.delay ) {
16454 delayedShow = this.delayedShow = setInterval(function() {
16455 if ( tooltip.is( ":visible" ) ) {
16456 position( positionOption.of );
16457 clearInterval( delayedShow );
16459 }, $.fx.interval );
16462 this._trigger( "open", event, { tooltip: tooltip } );
16465 _registerCloseHandlers: function( event, target ) {
16467 keyup: function( event ) {
16468 if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
16469 var fakeEvent = $.Event(event);
16470 fakeEvent.currentTarget = target[0];
16471 this.close( fakeEvent, true );
16476 // Only bind remove handler for delegated targets. Non-delegated
16477 // tooltips will handle this in destroy.
16478 if ( target[ 0 ] !== this.element[ 0 ] ) {
16479 events.remove = function() {
16480 this._removeTooltip( this._find( target ).tooltip );
16484 if ( !event || event.type === "mouseover" ) {
16485 events.mouseleave = "close";
16487 if ( !event || event.type === "focusin" ) {
16488 events.focusout = "close";
16490 this._on( true, target, events );
16493 close: function( event ) {
16496 target = $( event ? event.currentTarget : this.element ),
16497 tooltipData = this._find( target );
16499 // The tooltip may already be closed
16500 if ( !tooltipData ) {
16502 // We set ui-tooltip-open immediately upon open (in open()), but only set the
16503 // additional data once there's actually content to show (in _open()). So even if the
16504 // tooltip doesn't have full data, we always remove ui-tooltip-open in case we're in
16505 // the period between open() and _open().
16506 target.removeData( "ui-tooltip-open" );
16510 tooltip = tooltipData.tooltip;
16512 // disabling closes the tooltip, so we need to track when we're closing
16513 // to avoid an infinite loop in case the tooltip becomes disabled on close
16514 if ( tooltipData.closing ) {
16518 // Clear the interval for delayed tracking tooltips
16519 clearInterval( this.delayedShow );
16521 // only set title if we had one before (see comment in _open())
16522 // If the title attribute has changed since open(), don't restore
16523 if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) {
16524 target.attr( "title", target.data( "ui-tooltip-title" ) );
16527 this._removeDescribedBy( target );
16529 tooltipData.hiding = true;
16530 tooltip.stop( true );
16531 this._hide( tooltip, this.options.hide, function() {
16532 that._removeTooltip( $( this ) );
16535 target.removeData( "ui-tooltip-open" );
16536 this._off( target, "mouseleave focusout keyup" );
16538 // Remove 'remove' binding only on delegated targets
16539 if ( target[ 0 ] !== this.element[ 0 ] ) {
16540 this._off( target, "remove" );
16542 this._off( this.document, "mousemove" );
16544 if ( event && event.type === "mouseleave" ) {
16545 $.each( this.parents, function( id, parent ) {
16546 $( parent.element ).attr( "title", parent.title );
16547 delete that.parents[ id ];
16551 tooltipData.closing = true;
16552 this._trigger( "close", event, { tooltip: tooltip } );
16553 if ( !tooltipData.hiding ) {
16554 tooltipData.closing = false;
16558 _tooltip: function( element ) {
16559 var tooltip = $( "<div>" )
16560 .attr( "role", "tooltip" )
16561 .addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " +
16562 ( this.options.tooltipClass || "" ) ),
16563 id = tooltip.uniqueId().attr( "id" );
16566 .addClass( "ui-tooltip-content" )
16567 .appendTo( tooltip );
16569 tooltip.appendTo( this.document[0].body );
16571 return this.tooltips[ id ] = {
16577 _find: function( target ) {
16578 var id = target.data( "ui-tooltip-id" );
16579 return id ? this.tooltips[ id ] : null;
16582 _removeTooltip: function( tooltip ) {
16584 delete this.tooltips[ tooltip.attr( "id" ) ];
16587 _destroy: function() {
16590 // close open tooltips
16591 $.each( this.tooltips, function( id, tooltipData ) {
16592 // Delegate to close method to handle common cleanup
16593 var event = $.Event( "blur" ),
16594 element = tooltipData.element;
16595 event.target = event.currentTarget = element[ 0 ];
16596 that.close( event, true );
16598 // Remove immediately; destroying an open tooltip doesn't use the
16600 $( "#" + id ).remove();
16602 // Restore the title
16603 if ( element.data( "ui-tooltip-title" ) ) {
16604 // If the title attribute has changed since open(), don't restore
16605 if ( !element.attr( "title" ) ) {
16606 element.attr( "title", element.data( "ui-tooltip-title" ) );
16608 element.removeData( "ui-tooltip-title" );
16611 this.liveRegion.remove();