1 /*! jQuery UI - v1.11.2 - 2014-10-16
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 2014 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.2
21 * Copyright 2014 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.2
313 * http://jqueryui.com
315 * Copyright 2014 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 // allow multiple hashes to be passed on init
494 options = !isMethodCall && args.length ?
495 $.widget.extend.apply( null, [ options ].concat(args) ) :
498 if ( isMethodCall ) {
499 this.each(function() {
501 instance = $.data( this, fullName );
502 if ( options === "instance" ) {
503 returnValue = instance;
507 return $.error( "cannot call methods on " + name + " prior to initialization; " +
508 "attempted to call method '" + options + "'" );
510 if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
511 return $.error( "no such method '" + options + "' for " + name + " widget instance" );
513 methodValue = instance[ options ].apply( instance, args );
514 if ( methodValue !== instance && methodValue !== undefined ) {
515 returnValue = methodValue && methodValue.jquery ?
516 returnValue.pushStack( methodValue.get() ) :
522 this.each(function() {
523 var instance = $.data( this, fullName );
525 instance.option( options || {} );
526 if ( instance._init ) {
530 $.data( this, fullName, new object( options, this ) );
539 $.Widget = function( /* options, element */ ) {};
540 $.Widget._childConstructors = [];
542 $.Widget.prototype = {
543 widgetName: "widget",
544 widgetEventPrefix: "",
545 defaultElement: "<div>",
552 _createWidget: function( options, element ) {
553 element = $( element || this.defaultElement || this )[ 0 ];
554 this.element = $( element );
555 this.uuid = widget_uuid++;
556 this.eventNamespace = "." + this.widgetName + this.uuid;
559 this.hoverable = $();
560 this.focusable = $();
562 if ( element !== this ) {
563 $.data( element, this.widgetFullName, this );
564 this._on( true, this.element, {
565 remove: function( event ) {
566 if ( event.target === element ) {
571 this.document = $( element.style ?
572 // element within the document
573 element.ownerDocument :
574 // element is window or document
575 element.document || element );
576 this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
579 this.options = $.widget.extend( {},
581 this._getCreateOptions(),
585 this._trigger( "create", null, this._getCreateEventData() );
588 _getCreateOptions: $.noop,
589 _getCreateEventData: $.noop,
593 destroy: function() {
595 // we can probably remove the unbind calls in 2.0
596 // all event bindings should go through this._on()
598 .unbind( this.eventNamespace )
599 .removeData( this.widgetFullName )
600 // support: jquery <1.6.3
601 // http://bugs.jquery.com/ticket/9413
602 .removeData( $.camelCase( this.widgetFullName ) );
604 .unbind( this.eventNamespace )
605 .removeAttr( "aria-disabled" )
607 this.widgetFullName + "-disabled " +
608 "ui-state-disabled" );
610 // clean up events and states
611 this.bindings.unbind( this.eventNamespace );
612 this.hoverable.removeClass( "ui-state-hover" );
613 this.focusable.removeClass( "ui-state-focus" );
621 option: function( key, value ) {
627 if ( arguments.length === 0 ) {
628 // don't return a reference to the internal hash
629 return $.widget.extend( {}, this.options );
632 if ( typeof key === "string" ) {
633 // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
635 parts = key.split( "." );
637 if ( parts.length ) {
638 curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
639 for ( i = 0; i < parts.length - 1; i++ ) {
640 curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
641 curOption = curOption[ parts[ i ] ];
644 if ( arguments.length === 1 ) {
645 return curOption[ key ] === undefined ? null : curOption[ key ];
647 curOption[ key ] = value;
649 if ( arguments.length === 1 ) {
650 return this.options[ key ] === undefined ? null : this.options[ key ];
652 options[ key ] = value;
656 this._setOptions( options );
660 _setOptions: function( options ) {
663 for ( key in options ) {
664 this._setOption( key, options[ key ] );
669 _setOption: function( key, value ) {
670 this.options[ key ] = value;
672 if ( key === "disabled" ) {
674 .toggleClass( this.widgetFullName + "-disabled", !!value );
676 // If the widget is becoming disabled, then nothing is interactive
678 this.hoverable.removeClass( "ui-state-hover" );
679 this.focusable.removeClass( "ui-state-focus" );
687 return this._setOptions({ disabled: false });
689 disable: function() {
690 return this._setOptions({ disabled: true });
693 _on: function( suppressDisabledCheck, element, handlers ) {
697 // no suppressDisabledCheck flag, shuffle arguments
698 if ( typeof suppressDisabledCheck !== "boolean" ) {
700 element = suppressDisabledCheck;
701 suppressDisabledCheck = false;
704 // no element argument, shuffle and use this.element
707 element = this.element;
708 delegateElement = this.widget();
710 element = delegateElement = $( element );
711 this.bindings = this.bindings.add( element );
714 $.each( handlers, function( event, handler ) {
715 function handlerProxy() {
716 // allow widgets to customize the disabled handling
717 // - disabled as an array instead of boolean
718 // - disabled class as method for disabling individual parts
719 if ( !suppressDisabledCheck &&
720 ( instance.options.disabled === true ||
721 $( this ).hasClass( "ui-state-disabled" ) ) ) {
724 return ( typeof handler === "string" ? instance[ handler ] : handler )
725 .apply( instance, arguments );
728 // copy the guid so direct unbinding works
729 if ( typeof handler !== "string" ) {
730 handlerProxy.guid = handler.guid =
731 handler.guid || handlerProxy.guid || $.guid++;
734 var match = event.match( /^([\w:-]*)\s*(.*)$/ ),
735 eventName = match[1] + instance.eventNamespace,
738 delegateElement.delegate( selector, eventName, handlerProxy );
740 element.bind( eventName, handlerProxy );
745 _off: function( element, eventName ) {
746 eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) +
748 element.unbind( eventName ).undelegate( eventName );
750 // Clear the stack to avoid memory leaks (#10056)
751 this.bindings = $( this.bindings.not( element ).get() );
752 this.focusable = $( this.focusable.not( element ).get() );
753 this.hoverable = $( this.hoverable.not( element ).get() );
756 _delay: function( handler, delay ) {
757 function handlerProxy() {
758 return ( typeof handler === "string" ? instance[ handler ] : handler )
759 .apply( instance, arguments );
762 return setTimeout( handlerProxy, delay || 0 );
765 _hoverable: function( element ) {
766 this.hoverable = this.hoverable.add( element );
768 mouseenter: function( event ) {
769 $( event.currentTarget ).addClass( "ui-state-hover" );
771 mouseleave: function( event ) {
772 $( event.currentTarget ).removeClass( "ui-state-hover" );
777 _focusable: function( element ) {
778 this.focusable = this.focusable.add( element );
780 focusin: function( event ) {
781 $( event.currentTarget ).addClass( "ui-state-focus" );
783 focusout: function( event ) {
784 $( event.currentTarget ).removeClass( "ui-state-focus" );
789 _trigger: function( type, event, data ) {
791 callback = this.options[ type ];
794 event = $.Event( event );
795 event.type = ( type === this.widgetEventPrefix ?
797 this.widgetEventPrefix + type ).toLowerCase();
798 // the original event may come from any element
799 // so we need to reset the target on the new event
800 event.target = this.element[ 0 ];
802 // copy original event properties over to the new event
803 orig = event.originalEvent;
805 for ( prop in orig ) {
806 if ( !( prop in event ) ) {
807 event[ prop ] = orig[ prop ];
812 this.element.trigger( event, data );
813 return !( $.isFunction( callback ) &&
814 callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
815 event.isDefaultPrevented() );
819 $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
820 $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
821 if ( typeof options === "string" ) {
822 options = { effect: options };
825 effectName = !options ?
827 options === true || typeof options === "number" ?
829 options.effect || defaultEffect;
830 options = options || {};
831 if ( typeof options === "number" ) {
832 options = { duration: options };
834 hasOptions = !$.isEmptyObject( options );
835 options.complete = callback;
836 if ( options.delay ) {
837 element.delay( options.delay );
839 if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
840 element[ method ]( options );
841 } else if ( effectName !== method && element[ effectName ] ) {
842 element[ effectName ]( options.duration, options.easing, callback );
844 element.queue(function( next ) {
845 $( this )[ method ]();
847 callback.call( element[ 0 ] );
855 var widget = $.widget;
859 * jQuery UI Mouse 1.11.2
860 * http://jqueryui.com
862 * Copyright 2014 jQuery Foundation and other contributors
863 * Released under the MIT license.
864 * http://jquery.org/license
866 * http://api.jqueryui.com/mouse/
870 var mouseHandled = false;
871 $( document ).mouseup( function() {
872 mouseHandled = false;
875 var mouse = $.widget("ui.mouse", {
878 cancel: "input,textarea,button,select,option",
882 _mouseInit: function() {
886 .bind("mousedown." + this.widgetName, function(event) {
887 return that._mouseDown(event);
889 .bind("click." + this.widgetName, function(event) {
890 if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) {
891 $.removeData(event.target, that.widgetName + ".preventClickEvent");
892 event.stopImmediatePropagation();
897 this.started = false;
900 // TODO: make sure destroying one instance of mouse doesn't mess with
901 // other instances of mouse
902 _mouseDestroy: function() {
903 this.element.unbind("." + this.widgetName);
904 if ( this._mouseMoveDelegate ) {
906 .unbind("mousemove." + this.widgetName, this._mouseMoveDelegate)
907 .unbind("mouseup." + this.widgetName, this._mouseUpDelegate);
911 _mouseDown: function(event) {
912 // don't let more than one widget handle mouseStart
913 if ( mouseHandled ) {
917 this._mouseMoved = false;
919 // we may have missed mouseup (out of window)
920 (this._mouseStarted && this._mouseUp(event));
922 this._mouseDownEvent = event;
925 btnIsLeft = (event.which === 1),
926 // event.target.nodeName works around a bug in IE 8 with
927 // disabled inputs (#7620)
928 elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false);
929 if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
933 this.mouseDelayMet = !this.options.delay;
934 if (!this.mouseDelayMet) {
935 this._mouseDelayTimer = setTimeout(function() {
936 that.mouseDelayMet = true;
937 }, this.options.delay);
940 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
941 this._mouseStarted = (this._mouseStart(event) !== false);
942 if (!this._mouseStarted) {
943 event.preventDefault();
948 // Click event may never have fired (Gecko & Opera)
949 if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) {
950 $.removeData(event.target, this.widgetName + ".preventClickEvent");
953 // these delegates are required to keep context
954 this._mouseMoveDelegate = function(event) {
955 return that._mouseMove(event);
957 this._mouseUpDelegate = function(event) {
958 return that._mouseUp(event);
962 .bind( "mousemove." + this.widgetName, this._mouseMoveDelegate )
963 .bind( "mouseup." + this.widgetName, this._mouseUpDelegate );
965 event.preventDefault();
971 _mouseMove: function(event) {
972 // Only check for mouseups outside the document if you've moved inside the document
973 // at least once. This prevents the firing of mouseup in the case of IE<9, which will
974 // fire a mousemove event if content is placed under the cursor. See #7778
976 if ( this._mouseMoved ) {
977 // IE mouseup check - mouseup happened when mouse was out of window
978 if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) {
979 return this._mouseUp(event);
981 // Iframe mouseup check - mouseup occurred in another document
982 } else if ( !event.which ) {
983 return this._mouseUp( event );
987 if ( event.which || event.button ) {
988 this._mouseMoved = true;
991 if (this._mouseStarted) {
992 this._mouseDrag(event);
993 return event.preventDefault();
996 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
998 (this._mouseStart(this._mouseDownEvent, event) !== false);
999 (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
1002 return !this._mouseStarted;
1005 _mouseUp: function(event) {
1007 .unbind( "mousemove." + this.widgetName, this._mouseMoveDelegate )
1008 .unbind( "mouseup." + this.widgetName, this._mouseUpDelegate );
1010 if (this._mouseStarted) {
1011 this._mouseStarted = false;
1013 if (event.target === this._mouseDownEvent.target) {
1014 $.data(event.target, this.widgetName + ".preventClickEvent", true);
1017 this._mouseStop(event);
1020 mouseHandled = false;
1024 _mouseDistanceMet: function(event) {
1026 Math.abs(this._mouseDownEvent.pageX - event.pageX),
1027 Math.abs(this._mouseDownEvent.pageY - event.pageY)
1028 ) >= this.options.distance
1032 _mouseDelayMet: function(/* event */) {
1033 return this.mouseDelayMet;
1036 // These are placeholder methods, to be overriden by extending plugin
1037 _mouseStart: function(/* event */) {},
1038 _mouseDrag: function(/* event */) {},
1039 _mouseStop: function(/* event */) {},
1040 _mouseCapture: function(/* event */) { return true; }
1045 * jQuery UI Position 1.11.2
1046 * http://jqueryui.com
1048 * Copyright 2014 jQuery Foundation and other contributors
1049 * Released under the MIT license.
1050 * http://jquery.org/license
1052 * http://api.jqueryui.com/position/
1059 var cachedScrollbarWidth, supportsOffsetFractions,
1063 rhorizontal = /left|center|right/,
1064 rvertical = /top|center|bottom/,
1065 roffset = /[\+\-]\d+(\.[\d]+)?%?/,
1068 _position = $.fn.position;
1070 function getOffsets( offsets, width, height ) {
1072 parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
1073 parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
1077 function parseCss( element, property ) {
1078 return parseInt( $.css( element, property ), 10 ) || 0;
1081 function getDimensions( elem ) {
1083 if ( raw.nodeType === 9 ) {
1085 width: elem.width(),
1086 height: elem.height(),
1087 offset: { top: 0, left: 0 }
1090 if ( $.isWindow( raw ) ) {
1092 width: elem.width(),
1093 height: elem.height(),
1094 offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
1097 if ( raw.preventDefault ) {
1101 offset: { top: raw.pageY, left: raw.pageX }
1105 width: elem.outerWidth(),
1106 height: elem.outerHeight(),
1107 offset: elem.offset()
1112 scrollbarWidth: function() {
1113 if ( cachedScrollbarWidth !== undefined ) {
1114 return cachedScrollbarWidth;
1117 div = $( "<div style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ),
1118 innerDiv = div.children()[0];
1120 $( "body" ).append( div );
1121 w1 = innerDiv.offsetWidth;
1122 div.css( "overflow", "scroll" );
1124 w2 = innerDiv.offsetWidth;
1127 w2 = div[0].clientWidth;
1132 return (cachedScrollbarWidth = w1 - w2);
1134 getScrollInfo: function( within ) {
1135 var overflowX = within.isWindow || within.isDocument ? "" :
1136 within.element.css( "overflow-x" ),
1137 overflowY = within.isWindow || within.isDocument ? "" :
1138 within.element.css( "overflow-y" ),
1139 hasOverflowX = overflowX === "scroll" ||
1140 ( overflowX === "auto" && within.width < within.element[0].scrollWidth ),
1141 hasOverflowY = overflowY === "scroll" ||
1142 ( overflowY === "auto" && within.height < within.element[0].scrollHeight );
1144 width: hasOverflowY ? $.position.scrollbarWidth() : 0,
1145 height: hasOverflowX ? $.position.scrollbarWidth() : 0
1148 getWithinInfo: function( element ) {
1149 var withinElement = $( element || window ),
1150 isWindow = $.isWindow( withinElement[0] ),
1151 isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9;
1153 element: withinElement,
1155 isDocument: isDocument,
1156 offset: withinElement.offset() || { left: 0, top: 0 },
1157 scrollLeft: withinElement.scrollLeft(),
1158 scrollTop: withinElement.scrollTop(),
1160 // support: jQuery 1.6.x
1161 // jQuery 1.6 doesn't support .outerWidth/Height() on documents or windows
1162 width: isWindow || isDocument ? withinElement.width() : withinElement.outerWidth(),
1163 height: isWindow || isDocument ? withinElement.height() : withinElement.outerHeight()
1168 $.fn.position = function( options ) {
1169 if ( !options || !options.of ) {
1170 return _position.apply( this, arguments );
1173 // make a copy, we don't want to modify arguments
1174 options = $.extend( {}, options );
1176 var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
1177 target = $( options.of ),
1178 within = $.position.getWithinInfo( options.within ),
1179 scrollInfo = $.position.getScrollInfo( within ),
1180 collision = ( options.collision || "flip" ).split( " " ),
1183 dimensions = getDimensions( target );
1184 if ( target[0].preventDefault ) {
1185 // force left top to allow flipping
1186 options.at = "left top";
1188 targetWidth = dimensions.width;
1189 targetHeight = dimensions.height;
1190 targetOffset = dimensions.offset;
1191 // clone to reuse original targetOffset later
1192 basePosition = $.extend( {}, targetOffset );
1194 // force my and at to have valid horizontal and vertical positions
1195 // if a value is missing or invalid, it will be converted to center
1196 $.each( [ "my", "at" ], function() {
1197 var pos = ( options[ this ] || "" ).split( " " ),
1201 if ( pos.length === 1) {
1202 pos = rhorizontal.test( pos[ 0 ] ) ?
1203 pos.concat( [ "center" ] ) :
1204 rvertical.test( pos[ 0 ] ) ?
1205 [ "center" ].concat( pos ) :
1206 [ "center", "center" ];
1208 pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
1209 pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
1211 // calculate offsets
1212 horizontalOffset = roffset.exec( pos[ 0 ] );
1213 verticalOffset = roffset.exec( pos[ 1 ] );
1215 horizontalOffset ? horizontalOffset[ 0 ] : 0,
1216 verticalOffset ? verticalOffset[ 0 ] : 0
1219 // reduce to just the positions without the offsets
1221 rposition.exec( pos[ 0 ] )[ 0 ],
1222 rposition.exec( pos[ 1 ] )[ 0 ]
1226 // normalize collision option
1227 if ( collision.length === 1 ) {
1228 collision[ 1 ] = collision[ 0 ];
1231 if ( options.at[ 0 ] === "right" ) {
1232 basePosition.left += targetWidth;
1233 } else if ( options.at[ 0 ] === "center" ) {
1234 basePosition.left += targetWidth / 2;
1237 if ( options.at[ 1 ] === "bottom" ) {
1238 basePosition.top += targetHeight;
1239 } else if ( options.at[ 1 ] === "center" ) {
1240 basePosition.top += targetHeight / 2;
1243 atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
1244 basePosition.left += atOffset[ 0 ];
1245 basePosition.top += atOffset[ 1 ];
1247 return this.each(function() {
1248 var collisionPosition, using,
1250 elemWidth = elem.outerWidth(),
1251 elemHeight = elem.outerHeight(),
1252 marginLeft = parseCss( this, "marginLeft" ),
1253 marginTop = parseCss( this, "marginTop" ),
1254 collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width,
1255 collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height,
1256 position = $.extend( {}, basePosition ),
1257 myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
1259 if ( options.my[ 0 ] === "right" ) {
1260 position.left -= elemWidth;
1261 } else if ( options.my[ 0 ] === "center" ) {
1262 position.left -= elemWidth / 2;
1265 if ( options.my[ 1 ] === "bottom" ) {
1266 position.top -= elemHeight;
1267 } else if ( options.my[ 1 ] === "center" ) {
1268 position.top -= elemHeight / 2;
1271 position.left += myOffset[ 0 ];
1272 position.top += myOffset[ 1 ];
1274 // if the browser doesn't support fractions, then round for consistent results
1275 if ( !supportsOffsetFractions ) {
1276 position.left = round( position.left );
1277 position.top = round( position.top );
1280 collisionPosition = {
1281 marginLeft: marginLeft,
1282 marginTop: marginTop
1285 $.each( [ "left", "top" ], function( i, dir ) {
1286 if ( $.ui.position[ collision[ i ] ] ) {
1287 $.ui.position[ collision[ i ] ][ dir ]( position, {
1288 targetWidth: targetWidth,
1289 targetHeight: targetHeight,
1290 elemWidth: elemWidth,
1291 elemHeight: elemHeight,
1292 collisionPosition: collisionPosition,
1293 collisionWidth: collisionWidth,
1294 collisionHeight: collisionHeight,
1295 offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
1304 if ( options.using ) {
1305 // adds feedback as second argument to using callback, if present
1306 using = function( props ) {
1307 var left = targetOffset.left - position.left,
1308 right = left + targetWidth - elemWidth,
1309 top = targetOffset.top - position.top,
1310 bottom = top + targetHeight - elemHeight,
1314 left: targetOffset.left,
1315 top: targetOffset.top,
1317 height: targetHeight
1321 left: position.left,
1326 horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
1327 vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
1329 if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
1330 feedback.horizontal = "center";
1332 if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
1333 feedback.vertical = "middle";
1335 if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
1336 feedback.important = "horizontal";
1338 feedback.important = "vertical";
1340 options.using.call( this, props, feedback );
1344 elem.offset( $.extend( position, { using: using } ) );
1350 left: function( position, data ) {
1351 var within = data.within,
1352 withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
1353 outerWidth = within.width,
1354 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
1355 overLeft = withinOffset - collisionPosLeft,
1356 overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
1359 // element is wider than within
1360 if ( data.collisionWidth > outerWidth ) {
1361 // element is initially over the left side of within
1362 if ( overLeft > 0 && overRight <= 0 ) {
1363 newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
1364 position.left += overLeft - newOverRight;
1365 // element is initially over right side of within
1366 } else if ( overRight > 0 && overLeft <= 0 ) {
1367 position.left = withinOffset;
1368 // element is initially over both left and right sides of within
1370 if ( overLeft > overRight ) {
1371 position.left = withinOffset + outerWidth - data.collisionWidth;
1373 position.left = withinOffset;
1376 // too far left -> align with left edge
1377 } else if ( overLeft > 0 ) {
1378 position.left += overLeft;
1379 // too far right -> align with right edge
1380 } else if ( overRight > 0 ) {
1381 position.left -= overRight;
1382 // adjust based on position and margin
1384 position.left = max( position.left - collisionPosLeft, position.left );
1387 top: function( position, data ) {
1388 var within = data.within,
1389 withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
1390 outerHeight = data.within.height,
1391 collisionPosTop = position.top - data.collisionPosition.marginTop,
1392 overTop = withinOffset - collisionPosTop,
1393 overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
1396 // element is taller than within
1397 if ( data.collisionHeight > outerHeight ) {
1398 // element is initially over the top of within
1399 if ( overTop > 0 && overBottom <= 0 ) {
1400 newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
1401 position.top += overTop - newOverBottom;
1402 // element is initially over bottom of within
1403 } else if ( overBottom > 0 && overTop <= 0 ) {
1404 position.top = withinOffset;
1405 // element is initially over both top and bottom of within
1407 if ( overTop > overBottom ) {
1408 position.top = withinOffset + outerHeight - data.collisionHeight;
1410 position.top = withinOffset;
1413 // too far up -> align with top
1414 } else if ( overTop > 0 ) {
1415 position.top += overTop;
1416 // too far down -> align with bottom edge
1417 } else if ( overBottom > 0 ) {
1418 position.top -= overBottom;
1419 // adjust based on position and margin
1421 position.top = max( position.top - collisionPosTop, position.top );
1426 left: function( position, data ) {
1427 var within = data.within,
1428 withinOffset = within.offset.left + within.scrollLeft,
1429 outerWidth = within.width,
1430 offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
1431 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
1432 overLeft = collisionPosLeft - offsetLeft,
1433 overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
1434 myOffset = data.my[ 0 ] === "left" ?
1436 data.my[ 0 ] === "right" ?
1439 atOffset = data.at[ 0 ] === "left" ?
1441 data.at[ 0 ] === "right" ?
1444 offset = -2 * data.offset[ 0 ],
1448 if ( overLeft < 0 ) {
1449 newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
1450 if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
1451 position.left += myOffset + atOffset + offset;
1453 } else if ( overRight > 0 ) {
1454 newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;
1455 if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
1456 position.left += myOffset + atOffset + offset;
1460 top: function( position, data ) {
1461 var within = data.within,
1462 withinOffset = within.offset.top + within.scrollTop,
1463 outerHeight = within.height,
1464 offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
1465 collisionPosTop = position.top - data.collisionPosition.marginTop,
1466 overTop = collisionPosTop - offsetTop,
1467 overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
1468 top = data.my[ 1 ] === "top",
1471 data.my[ 1 ] === "bottom" ?
1474 atOffset = data.at[ 1 ] === "top" ?
1476 data.at[ 1 ] === "bottom" ?
1477 -data.targetHeight :
1479 offset = -2 * data.offset[ 1 ],
1482 if ( overTop < 0 ) {
1483 newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
1484 if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) {
1485 position.top += myOffset + atOffset + offset;
1487 } else if ( overBottom > 0 ) {
1488 newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;
1489 if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) {
1490 position.top += myOffset + atOffset + offset;
1497 $.ui.position.flip.left.apply( this, arguments );
1498 $.ui.position.fit.left.apply( this, arguments );
1501 $.ui.position.flip.top.apply( this, arguments );
1502 $.ui.position.fit.top.apply( this, arguments );
1507 // fraction support test
1509 var testElement, testElementParent, testElementStyle, offsetLeft, i,
1510 body = document.getElementsByTagName( "body" )[ 0 ],
1511 div = document.createElement( "div" );
1513 //Create a "fake body" for testing based on method used in jQuery.support
1514 testElement = document.createElement( body ? "div" : "body" );
1515 testElementStyle = {
1516 visibility: "hidden",
1524 $.extend( testElementStyle, {
1525 position: "absolute",
1530 for ( i in testElementStyle ) {
1531 testElement.style[ i ] = testElementStyle[ i ];
1533 testElement.appendChild( div );
1534 testElementParent = body || document.documentElement;
1535 testElementParent.insertBefore( testElement, testElementParent.firstChild );
1537 div.style.cssText = "position: absolute; left: 10.7432222px;";
1539 offsetLeft = $( div ).offset().left;
1540 supportsOffsetFractions = offsetLeft > 10 && offsetLeft < 11;
1542 testElement.innerHTML = "";
1543 testElementParent.removeChild( testElement );
1548 var position = $.ui.position;
1552 * jQuery UI Accordion 1.11.2
1553 * http://jqueryui.com
1555 * Copyright 2014 jQuery Foundation and other contributors
1556 * Released under the MIT license.
1557 * http://jquery.org/license
1559 * http://api.jqueryui.com/accordion/
1563 var accordion = $.widget( "ui.accordion", {
1570 header: "> li > :first-child,> :not(li):even",
1571 heightStyle: "auto",
1573 activeHeader: "ui-icon-triangle-1-s",
1574 header: "ui-icon-triangle-1-e"
1579 beforeActivate: null
1583 borderTopWidth: "hide",
1584 borderBottomWidth: "hide",
1586 paddingBottom: "hide",
1591 borderTopWidth: "show",
1592 borderBottomWidth: "show",
1594 paddingBottom: "show",
1598 _create: function() {
1599 var options = this.options;
1600 this.prevShow = this.prevHide = $();
1601 this.element.addClass( "ui-accordion ui-widget ui-helper-reset" )
1603 .attr( "role", "tablist" );
1605 // don't allow collapsible: false and active: false / null
1606 if ( !options.collapsible && (options.active === false || options.active == null) ) {
1610 this._processPanels();
1611 // handle negative values
1612 if ( options.active < 0 ) {
1613 options.active += this.headers.length;
1618 _getCreateEventData: function() {
1620 header: this.active,
1621 panel: !this.active.length ? $() : this.active.next()
1625 _createIcons: function() {
1626 var icons = this.options.icons;
1629 .addClass( "ui-accordion-header-icon ui-icon " + icons.header )
1630 .prependTo( this.headers );
1631 this.active.children( ".ui-accordion-header-icon" )
1632 .removeClass( icons.header )
1633 .addClass( icons.activeHeader );
1634 this.headers.addClass( "ui-accordion-icons" );
1638 _destroyIcons: function() {
1640 .removeClass( "ui-accordion-icons" )
1641 .children( ".ui-accordion-header-icon" )
1645 _destroy: function() {
1648 // clean up main element
1650 .removeClass( "ui-accordion ui-widget ui-helper-reset" )
1651 .removeAttr( "role" );
1655 .removeClass( "ui-accordion-header ui-accordion-header-active ui-state-default " +
1656 "ui-corner-all ui-state-active ui-state-disabled ui-corner-top" )
1657 .removeAttr( "role" )
1658 .removeAttr( "aria-expanded" )
1659 .removeAttr( "aria-selected" )
1660 .removeAttr( "aria-controls" )
1661 .removeAttr( "tabIndex" )
1664 this._destroyIcons();
1666 // clean up content panels
1667 contents = this.headers.next()
1668 .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom " +
1669 "ui-accordion-content ui-accordion-content-active ui-state-disabled" )
1670 .css( "display", "" )
1671 .removeAttr( "role" )
1672 .removeAttr( "aria-hidden" )
1673 .removeAttr( "aria-labelledby" )
1676 if ( this.options.heightStyle !== "content" ) {
1677 contents.css( "height", "" );
1681 _setOption: function( key, value ) {
1682 if ( key === "active" ) {
1683 // _activate() will handle invalid values and update this.options
1684 this._activate( value );
1688 if ( key === "event" ) {
1689 if ( this.options.event ) {
1690 this._off( this.headers, this.options.event );
1692 this._setupEvents( value );
1695 this._super( key, value );
1697 // setting collapsible: false while collapsed; open first panel
1698 if ( key === "collapsible" && !value && this.options.active === false ) {
1699 this._activate( 0 );
1702 if ( key === "icons" ) {
1703 this._destroyIcons();
1705 this._createIcons();
1709 // #5332 - opacity doesn't cascade to positioned elements in IE
1710 // so we need to add the disabled class to the headers and panels
1711 if ( key === "disabled" ) {
1713 .toggleClass( "ui-state-disabled", !!value )
1714 .attr( "aria-disabled", value );
1715 this.headers.add( this.headers.next() )
1716 .toggleClass( "ui-state-disabled", !!value );
1720 _keydown: function( event ) {
1721 if ( event.altKey || event.ctrlKey ) {
1725 var keyCode = $.ui.keyCode,
1726 length = this.headers.length,
1727 currentIndex = this.headers.index( event.target ),
1730 switch ( event.keyCode ) {
1733 toFocus = this.headers[ ( currentIndex + 1 ) % length ];
1737 toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
1741 this._eventHandler( event );
1744 toFocus = this.headers[ 0 ];
1747 toFocus = this.headers[ length - 1 ];
1752 $( event.target ).attr( "tabIndex", -1 );
1753 $( toFocus ).attr( "tabIndex", 0 );
1755 event.preventDefault();
1759 _panelKeyDown: function( event ) {
1760 if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
1761 $( event.currentTarget ).prev().focus();
1765 refresh: function() {
1766 var options = this.options;
1767 this._processPanels();
1769 // was collapsed or no panel
1770 if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) {
1771 options.active = false;
1773 // active false only when collapsible is true
1774 } else if ( options.active === false ) {
1775 this._activate( 0 );
1776 // was active, but active panel is gone
1777 } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
1778 // all remaining panel are disabled
1779 if ( this.headers.length === this.headers.find(".ui-state-disabled").length ) {
1780 options.active = false;
1782 // activate previous panel
1784 this._activate( Math.max( 0, options.active - 1 ) );
1786 // was active, active panel still exists
1788 // make sure active index is correct
1789 options.active = this.headers.index( this.active );
1792 this._destroyIcons();
1797 _processPanels: function() {
1798 var prevHeaders = this.headers,
1799 prevPanels = this.panels;
1801 this.headers = this.element.find( this.options.header )
1802 .addClass( "ui-accordion-header ui-state-default ui-corner-all" );
1804 this.panels = this.headers.next()
1805 .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" )
1806 .filter( ":not(.ui-accordion-content-active)" )
1809 // Avoid memory leaks (#10056)
1811 this._off( prevHeaders.not( this.headers ) );
1812 this._off( prevPanels.not( this.panels ) );
1816 _refresh: function() {
1818 options = this.options,
1819 heightStyle = options.heightStyle,
1820 parent = this.element.parent();
1822 this.active = this._findActive( options.active )
1823 .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" )
1824 .removeClass( "ui-corner-all" );
1826 .addClass( "ui-accordion-content-active" )
1830 .attr( "role", "tab" )
1832 var header = $( this ),
1833 headerId = header.uniqueId().attr( "id" ),
1834 panel = header.next(),
1835 panelId = panel.uniqueId().attr( "id" );
1836 header.attr( "aria-controls", panelId );
1837 panel.attr( "aria-labelledby", headerId );
1840 .attr( "role", "tabpanel" );
1845 "aria-selected": "false",
1846 "aria-expanded": "false",
1851 "aria-hidden": "true"
1855 // make sure at least one header is in the tab order
1856 if ( !this.active.length ) {
1857 this.headers.eq( 0 ).attr( "tabIndex", 0 );
1860 "aria-selected": "true",
1861 "aria-expanded": "true",
1866 "aria-hidden": "false"
1870 this._createIcons();
1872 this._setupEvents( options.event );
1874 if ( heightStyle === "fill" ) {
1875 maxHeight = parent.height();
1876 this.element.siblings( ":visible" ).each(function() {
1877 var elem = $( this ),
1878 position = elem.css( "position" );
1880 if ( position === "absolute" || position === "fixed" ) {
1883 maxHeight -= elem.outerHeight( true );
1886 this.headers.each(function() {
1887 maxHeight -= $( this ).outerHeight( true );
1892 $( this ).height( Math.max( 0, maxHeight -
1893 $( this ).innerHeight() + $( this ).height() ) );
1895 .css( "overflow", "auto" );
1896 } else if ( heightStyle === "auto" ) {
1900 maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
1902 .height( maxHeight );
1906 _activate: function( index ) {
1907 var active = this._findActive( index )[ 0 ];
1909 // trying to activate the already active panel
1910 if ( active === this.active[ 0 ] ) {
1914 // trying to collapse, simulate a click on the currently active header
1915 active = active || this.active[ 0 ];
1917 this._eventHandler({
1919 currentTarget: active,
1920 preventDefault: $.noop
1924 _findActive: function( selector ) {
1925 return typeof selector === "number" ? this.headers.eq( selector ) : $();
1928 _setupEvents: function( event ) {
1933 $.each( event.split( " " ), function( index, eventName ) {
1934 events[ eventName ] = "_eventHandler";
1938 this._off( this.headers.add( this.headers.next() ) );
1939 this._on( this.headers, events );
1940 this._on( this.headers.next(), { keydown: "_panelKeyDown" });
1941 this._hoverable( this.headers );
1942 this._focusable( this.headers );
1945 _eventHandler: function( event ) {
1946 var options = this.options,
1947 active = this.active,
1948 clicked = $( event.currentTarget ),
1949 clickedIsActive = clicked[ 0 ] === active[ 0 ],
1950 collapsing = clickedIsActive && options.collapsible,
1951 toShow = collapsing ? $() : clicked.next(),
1952 toHide = active.next(),
1956 newHeader: collapsing ? $() : clicked,
1960 event.preventDefault();
1963 // click on active header, but not collapsible
1964 ( clickedIsActive && !options.collapsible ) ||
1965 // allow canceling activation
1966 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
1970 options.active = collapsing ? false : this.headers.index( clicked );
1972 // when the call to ._toggle() comes after the class changes
1973 // it causes a very odd bug in IE 8 (see #6720)
1974 this.active = clickedIsActive ? $() : clicked;
1975 this._toggle( eventData );
1978 // corner classes on the previously active header stay after the animation
1979 active.removeClass( "ui-accordion-header-active ui-state-active" );
1980 if ( options.icons ) {
1981 active.children( ".ui-accordion-header-icon" )
1982 .removeClass( options.icons.activeHeader )
1983 .addClass( options.icons.header );
1986 if ( !clickedIsActive ) {
1988 .removeClass( "ui-corner-all" )
1989 .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" );
1990 if ( options.icons ) {
1991 clicked.children( ".ui-accordion-header-icon" )
1992 .removeClass( options.icons.header )
1993 .addClass( options.icons.activeHeader );
1998 .addClass( "ui-accordion-content-active" );
2002 _toggle: function( data ) {
2003 var toShow = data.newPanel,
2004 toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
2006 // handle activating a panel during the animation for another activation
2007 this.prevShow.add( this.prevHide ).stop( true, true );
2008 this.prevShow = toShow;
2009 this.prevHide = toHide;
2011 if ( this.options.animate ) {
2012 this._animate( toShow, toHide, data );
2016 this._toggleComplete( data );
2020 "aria-hidden": "true"
2022 toHide.prev().attr( "aria-selected", "false" );
2023 // if we're switching panels, remove the old header from the tab order
2024 // if we're opening from collapsed state, remove the previous header from the tab order
2025 // if we're collapsing, then keep the collapsing header in the tab order
2026 if ( toShow.length && toHide.length ) {
2027 toHide.prev().attr({
2029 "aria-expanded": "false"
2031 } else if ( toShow.length ) {
2032 this.headers.filter(function() {
2033 return $( this ).attr( "tabIndex" ) === 0;
2035 .attr( "tabIndex", -1 );
2039 .attr( "aria-hidden", "false" )
2042 "aria-selected": "true",
2044 "aria-expanded": "true"
2048 _animate: function( toShow, toHide, data ) {
2049 var total, easing, duration,
2052 down = toShow.length &&
2053 ( !toHide.length || ( toShow.index() < toHide.index() ) ),
2054 animate = this.options.animate || {},
2055 options = down && animate.down || animate,
2056 complete = function() {
2057 that._toggleComplete( data );
2060 if ( typeof options === "number" ) {
2063 if ( typeof options === "string" ) {
2066 // fall back from options to animation in case of partial down settings
2067 easing = easing || options.easing || animate.easing;
2068 duration = duration || options.duration || animate.duration;
2070 if ( !toHide.length ) {
2071 return toShow.animate( this.showProps, duration, easing, complete );
2073 if ( !toShow.length ) {
2074 return toHide.animate( this.hideProps, duration, easing, complete );
2077 total = toShow.show().outerHeight();
2078 toHide.animate( this.hideProps, {
2081 step: function( now, fx ) {
2082 fx.now = Math.round( now );
2087 .animate( this.showProps, {
2091 step: function( now, fx ) {
2092 fx.now = Math.round( now );
2093 if ( fx.prop !== "height" ) {
2095 } else if ( that.options.heightStyle !== "content" ) {
2096 fx.now = Math.round( total - toHide.outerHeight() - adjust );
2103 _toggleComplete: function( data ) {
2104 var toHide = data.oldPanel;
2107 .removeClass( "ui-accordion-content-active" )
2109 .removeClass( "ui-corner-top" )
2110 .addClass( "ui-corner-all" );
2112 // Work around for rendering bug in IE (#5421)
2113 if ( toHide.length ) {
2114 toHide.parent()[ 0 ].className = toHide.parent()[ 0 ].className;
2116 this._trigger( "activate", null, data );
2122 * jQuery UI Menu 1.11.2
2123 * http://jqueryui.com
2125 * Copyright 2014 jQuery Foundation and other contributors
2126 * Released under the MIT license.
2127 * http://jquery.org/license
2129 * http://api.jqueryui.com/menu/
2133 var menu = $.widget( "ui.menu", {
2135 defaultElement: "<ul>",
2139 submenu: "ui-icon-carat-1-e"
2155 _create: function() {
2156 this.activeMenu = this.element;
2158 // Flag used to prevent firing of the click handler
2159 // as the event bubbles up through nested menus
2160 this.mouseHandled = false;
2163 .addClass( "ui-menu ui-widget ui-widget-content" )
2164 .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length )
2166 role: this.options.role,
2170 if ( this.options.disabled ) {
2172 .addClass( "ui-state-disabled" )
2173 .attr( "aria-disabled", "true" );
2177 // Prevent focus from sticking to links inside menu after clicking
2178 // them (focus should always stay on UL during navigation).
2179 "mousedown .ui-menu-item": function( event ) {
2180 event.preventDefault();
2182 "click .ui-menu-item": function( event ) {
2183 var target = $( event.target );
2184 if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
2185 this.select( event );
2187 // Only set the mouseHandled flag if the event will bubble, see #9469.
2188 if ( !event.isPropagationStopped() ) {
2189 this.mouseHandled = true;
2192 // Open submenu on click
2193 if ( target.has( ".ui-menu" ).length ) {
2194 this.expand( event );
2195 } else if ( !this.element.is( ":focus" ) && $( this.document[ 0 ].activeElement ).closest( ".ui-menu" ).length ) {
2197 // Redirect focus to the menu
2198 this.element.trigger( "focus", [ true ] );
2200 // If the active item is on the top level, let it stay active.
2201 // Otherwise, blur the active item since it is no longer visible.
2202 if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
2203 clearTimeout( this.timer );
2208 "mouseenter .ui-menu-item": function( event ) {
2209 // Ignore mouse events while typeahead is active, see #10458.
2210 // Prevents focusing the wrong item when typeahead causes a scroll while the mouse
2211 // is over an item in the menu
2212 if ( this.previousFilter ) {
2215 var target = $( event.currentTarget );
2216 // Remove ui-state-active class from siblings of the newly focused menu item
2217 // to avoid a jump caused by adjacent elements both having a class with a border
2218 target.siblings( ".ui-state-active" ).removeClass( "ui-state-active" );
2219 this.focus( event, target );
2221 mouseleave: "collapseAll",
2222 "mouseleave .ui-menu": "collapseAll",
2223 focus: function( event, keepActiveItem ) {
2224 // If there's already an active item, keep it active
2225 // If not, activate the first item
2226 var item = this.active || this.element.find( this.options.items ).eq( 0 );
2228 if ( !keepActiveItem ) {
2229 this.focus( event, item );
2232 blur: function( event ) {
2233 this._delay(function() {
2234 if ( !$.contains( this.element[0], this.document[0].activeElement ) ) {
2235 this.collapseAll( event );
2244 // Clicks outside of a menu collapse any open menus
2245 this._on( this.document, {
2246 click: function( event ) {
2247 if ( this._closeOnDocumentClick( event ) ) {
2248 this.collapseAll( event );
2251 // Reset the mouseHandled flag
2252 this.mouseHandled = false;
2257 _destroy: function() {
2258 // Destroy (sub)menus
2260 .removeAttr( "aria-activedescendant" )
2261 .find( ".ui-menu" ).addBack()
2262 .removeClass( "ui-menu ui-widget ui-widget-content ui-menu-icons ui-front" )
2263 .removeAttr( "role" )
2264 .removeAttr( "tabIndex" )
2265 .removeAttr( "aria-labelledby" )
2266 .removeAttr( "aria-expanded" )
2267 .removeAttr( "aria-hidden" )
2268 .removeAttr( "aria-disabled" )
2272 // Destroy menu items
2273 this.element.find( ".ui-menu-item" )
2274 .removeClass( "ui-menu-item" )
2275 .removeAttr( "role" )
2276 .removeAttr( "aria-disabled" )
2278 .removeClass( "ui-state-hover" )
2279 .removeAttr( "tabIndex" )
2280 .removeAttr( "role" )
2281 .removeAttr( "aria-haspopup" )
2282 .children().each( function() {
2283 var elem = $( this );
2284 if ( elem.data( "ui-menu-submenu-carat" ) ) {
2289 // Destroy menu dividers
2290 this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" );
2293 _keydown: function( event ) {
2294 var match, prev, character, skip,
2295 preventDefault = true;
2297 switch ( event.keyCode ) {
2298 case $.ui.keyCode.PAGE_UP:
2299 this.previousPage( event );
2301 case $.ui.keyCode.PAGE_DOWN:
2302 this.nextPage( event );
2304 case $.ui.keyCode.HOME:
2305 this._move( "first", "first", event );
2307 case $.ui.keyCode.END:
2308 this._move( "last", "last", event );
2310 case $.ui.keyCode.UP:
2311 this.previous( event );
2313 case $.ui.keyCode.DOWN:
2316 case $.ui.keyCode.LEFT:
2317 this.collapse( event );
2319 case $.ui.keyCode.RIGHT:
2320 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
2321 this.expand( event );
2324 case $.ui.keyCode.ENTER:
2325 case $.ui.keyCode.SPACE:
2326 this._activate( event );
2328 case $.ui.keyCode.ESCAPE:
2329 this.collapse( event );
2332 preventDefault = false;
2333 prev = this.previousFilter || "";
2334 character = String.fromCharCode( event.keyCode );
2337 clearTimeout( this.filterTimer );
2339 if ( character === prev ) {
2342 character = prev + character;
2345 match = this._filterMenuItems( character );
2346 match = skip && match.index( this.active.next() ) !== -1 ?
2347 this.active.nextAll( ".ui-menu-item" ) :
2350 // If no matches on the current filter, reset to the last character pressed
2351 // to move down the menu to the first item that starts with that character
2352 if ( !match.length ) {
2353 character = String.fromCharCode( event.keyCode );
2354 match = this._filterMenuItems( character );
2357 if ( match.length ) {
2358 this.focus( event, match );
2359 this.previousFilter = character;
2360 this.filterTimer = this._delay(function() {
2361 delete this.previousFilter;
2364 delete this.previousFilter;
2368 if ( preventDefault ) {
2369 event.preventDefault();
2373 _activate: function( event ) {
2374 if ( !this.active.is( ".ui-state-disabled" ) ) {
2375 if ( this.active.is( "[aria-haspopup='true']" ) ) {
2376 this.expand( event );
2378 this.select( event );
2383 refresh: function() {
2386 icon = this.options.icons.submenu,
2387 submenus = this.element.find( this.options.menus );
2389 this.element.toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length );
2391 // Initialize nested menus
2392 submenus.filter( ":not(.ui-menu)" )
2393 .addClass( "ui-menu ui-widget ui-widget-content ui-front" )
2396 role: this.options.role,
2397 "aria-hidden": "true",
2398 "aria-expanded": "false"
2401 var menu = $( this ),
2402 item = menu.parent(),
2403 submenuCarat = $( "<span>" )
2404 .addClass( "ui-menu-icon ui-icon " + icon )
2405 .data( "ui-menu-submenu-carat", true );
2408 .attr( "aria-haspopup", "true" )
2409 .prepend( submenuCarat );
2410 menu.attr( "aria-labelledby", item.attr( "id" ) );
2413 menus = submenus.add( this.element );
2414 items = menus.find( this.options.items );
2416 // Initialize menu-items containing spaces and/or dashes only as dividers
2417 items.not( ".ui-menu-item" ).each(function() {
2418 var item = $( this );
2419 if ( that._isDivider( item ) ) {
2420 item.addClass( "ui-widget-content ui-menu-divider" );
2424 // Don't refresh list items that are already adapted
2425 items.not( ".ui-menu-item, .ui-menu-divider" )
2426 .addClass( "ui-menu-item" )
2430 role: this._itemRole()
2433 // Add aria-disabled attribute to any disabled menu item
2434 items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
2436 // If the active item has been removed, blur the menu
2437 if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
2442 _itemRole: function() {
2446 }[ this.options.role ];
2449 _setOption: function( key, value ) {
2450 if ( key === "icons" ) {
2451 this.element.find( ".ui-menu-icon" )
2452 .removeClass( this.options.icons.submenu )
2453 .addClass( value.submenu );
2455 if ( key === "disabled" ) {
2457 .toggleClass( "ui-state-disabled", !!value )
2458 .attr( "aria-disabled", value );
2460 this._super( key, value );
2463 focus: function( event, item ) {
2464 var nested, focused;
2465 this.blur( event, event && event.type === "focus" );
2467 this._scrollIntoView( item );
2469 this.active = item.first();
2470 focused = this.active.addClass( "ui-state-focus" ).removeClass( "ui-state-active" );
2471 // Only update aria-activedescendant if there's a role
2472 // otherwise we assume focus is managed elsewhere
2473 if ( this.options.role ) {
2474 this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
2477 // Highlight active parent menu item, if any
2480 .closest( ".ui-menu-item" )
2481 .addClass( "ui-state-active" );
2483 if ( event && event.type === "keydown" ) {
2486 this.timer = this._delay(function() {
2491 nested = item.children( ".ui-menu" );
2492 if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) {
2493 this._startOpening(nested);
2495 this.activeMenu = item.parent();
2497 this._trigger( "focus", event, { item: item } );
2500 _scrollIntoView: function( item ) {
2501 var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
2502 if ( this._hasScroll() ) {
2503 borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0;
2504 paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0;
2505 offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
2506 scroll = this.activeMenu.scrollTop();
2507 elementHeight = this.activeMenu.height();
2508 itemHeight = item.outerHeight();
2511 this.activeMenu.scrollTop( scroll + offset );
2512 } else if ( offset + itemHeight > elementHeight ) {
2513 this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
2518 blur: function( event, fromFocus ) {
2520 clearTimeout( this.timer );
2523 if ( !this.active ) {
2527 this.active.removeClass( "ui-state-focus" );
2530 this._trigger( "blur", event, { item: this.active } );
2533 _startOpening: function( submenu ) {
2534 clearTimeout( this.timer );
2536 // Don't open if already open fixes a Firefox bug that caused a .5 pixel
2537 // shift in the submenu position when mousing over the carat icon
2538 if ( submenu.attr( "aria-hidden" ) !== "true" ) {
2542 this.timer = this._delay(function() {
2544 this._open( submenu );
2548 _open: function( submenu ) {
2549 var position = $.extend({
2551 }, this.options.position );
2553 clearTimeout( this.timer );
2554 this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
2556 .attr( "aria-hidden", "true" );
2560 .removeAttr( "aria-hidden" )
2561 .attr( "aria-expanded", "true" )
2562 .position( position );
2565 collapseAll: function( event, all ) {
2566 clearTimeout( this.timer );
2567 this.timer = this._delay(function() {
2568 // If we were passed an event, look for the submenu that contains the event
2569 var currentMenu = all ? this.element :
2570 $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
2572 // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway
2573 if ( !currentMenu.length ) {
2574 currentMenu = this.element;
2577 this._close( currentMenu );
2580 this.activeMenu = currentMenu;
2584 // With no arguments, closes the currently active menu - if nothing is active
2585 // it closes all menus. If passed an argument, it will search for menus BELOW
2586 _close: function( startMenu ) {
2588 startMenu = this.active ? this.active.parent() : this.element;
2594 .attr( "aria-hidden", "true" )
2595 .attr( "aria-expanded", "false" )
2597 .find( ".ui-state-active" ).not( ".ui-state-focus" )
2598 .removeClass( "ui-state-active" );
2601 _closeOnDocumentClick: function( event ) {
2602 return !$( event.target ).closest( ".ui-menu" ).length;
2605 _isDivider: function( item ) {
2607 // Match hyphen, em dash, en dash
2608 return !/[^\-\u2014\u2013\s]/.test( item.text() );
2611 collapse: function( event ) {
2612 var newItem = this.active &&
2613 this.active.parent().closest( ".ui-menu-item", this.element );
2614 if ( newItem && newItem.length ) {
2616 this.focus( event, newItem );
2620 expand: function( event ) {
2621 var newItem = this.active &&
2623 .children( ".ui-menu " )
2624 .find( this.options.items )
2627 if ( newItem && newItem.length ) {
2628 this._open( newItem.parent() );
2630 // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
2631 this._delay(function() {
2632 this.focus( event, newItem );
2637 next: function( event ) {
2638 this._move( "next", "first", event );
2641 previous: function( event ) {
2642 this._move( "prev", "last", event );
2645 isFirstItem: function() {
2646 return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
2649 isLastItem: function() {
2650 return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
2653 _move: function( direction, filter, event ) {
2655 if ( this.active ) {
2656 if ( direction === "first" || direction === "last" ) {
2658 [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
2662 [ direction + "All" ]( ".ui-menu-item" )
2666 if ( !next || !next.length || !this.active ) {
2667 next = this.activeMenu.find( this.options.items )[ filter ]();
2670 this.focus( event, next );
2673 nextPage: function( event ) {
2674 var item, base, height;
2676 if ( !this.active ) {
2680 if ( this.isLastItem() ) {
2683 if ( this._hasScroll() ) {
2684 base = this.active.offset().top;
2685 height = this.element.height();
2686 this.active.nextAll( ".ui-menu-item" ).each(function() {
2688 return item.offset().top - base - height < 0;
2691 this.focus( event, item );
2693 this.focus( event, this.activeMenu.find( this.options.items )
2694 [ !this.active ? "first" : "last" ]() );
2698 previousPage: function( event ) {
2699 var item, base, height;
2700 if ( !this.active ) {
2704 if ( this.isFirstItem() ) {
2707 if ( this._hasScroll() ) {
2708 base = this.active.offset().top;
2709 height = this.element.height();
2710 this.active.prevAll( ".ui-menu-item" ).each(function() {
2712 return item.offset().top - base + height > 0;
2715 this.focus( event, item );
2717 this.focus( event, this.activeMenu.find( this.options.items ).first() );
2721 _hasScroll: function() {
2722 return this.element.outerHeight() < this.element.prop( "scrollHeight" );
2725 select: function( event ) {
2726 // TODO: It should never be possible to not have an active item at this
2727 // point, but the tests don't trigger mouseenter before click.
2728 this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
2729 var ui = { item: this.active };
2730 if ( !this.active.has( ".ui-menu" ).length ) {
2731 this.collapseAll( event, true );
2733 this._trigger( "select", event, ui );
2736 _filterMenuItems: function(character) {
2737 var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ),
2738 regex = new RegExp( "^" + escapedCharacter, "i" );
2740 return this.activeMenu
2741 .find( this.options.items )
2743 // Only match on items, not dividers or other content (#10571)
2744 .filter( ".ui-menu-item" )
2745 .filter(function() {
2746 return regex.test( $.trim( $( this ).text() ) );
2753 * jQuery UI Autocomplete 1.11.2
2754 * http://jqueryui.com
2756 * Copyright 2014 jQuery Foundation and other contributors
2757 * Released under the MIT license.
2758 * http://jquery.org/license
2760 * http://api.jqueryui.com/autocomplete/
2764 $.widget( "ui.autocomplete", {
2766 defaultElement: "<input>",
2792 _create: function() {
2793 // Some browsers only repeat keydown events, not keypress events,
2794 // so we use the suppressKeyPress flag to determine if we've already
2795 // handled the keydown event. #7269
2796 // Unfortunately the code for & in keypress is the same as the up arrow,
2797 // so we use the suppressKeyPressRepeat flag to avoid handling keypress
2798 // events when we know the keydown event was used to modify the
2799 // search term. #7799
2800 var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
2801 nodeName = this.element[ 0 ].nodeName.toLowerCase(),
2802 isTextarea = nodeName === "textarea",
2803 isInput = nodeName === "input";
2806 // Textareas are always multi-line
2808 // Inputs are always single-line, even if inside a contentEditable element
2809 // IE also treats inputs as contentEditable
2811 // All other element types are determined by whether or not they're contentEditable
2812 this.element.prop( "isContentEditable" );
2814 this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
2815 this.isNewMenu = true;
2818 .addClass( "ui-autocomplete-input" )
2819 .attr( "autocomplete", "off" );
2821 this._on( this.element, {
2822 keydown: function( event ) {
2823 if ( this.element.prop( "readOnly" ) ) {
2824 suppressKeyPress = true;
2825 suppressInput = true;
2826 suppressKeyPressRepeat = true;
2830 suppressKeyPress = false;
2831 suppressInput = false;
2832 suppressKeyPressRepeat = false;
2833 var keyCode = $.ui.keyCode;
2834 switch ( event.keyCode ) {
2835 case keyCode.PAGE_UP:
2836 suppressKeyPress = true;
2837 this._move( "previousPage", event );
2839 case keyCode.PAGE_DOWN:
2840 suppressKeyPress = true;
2841 this._move( "nextPage", event );
2844 suppressKeyPress = true;
2845 this._keyEvent( "previous", event );
2848 suppressKeyPress = true;
2849 this._keyEvent( "next", event );
2852 // when menu is open and has focus
2853 if ( this.menu.active ) {
2854 // #6055 - Opera still allows the keypress to occur
2855 // which causes forms to submit
2856 suppressKeyPress = true;
2857 event.preventDefault();
2858 this.menu.select( event );
2862 if ( this.menu.active ) {
2863 this.menu.select( event );
2866 case keyCode.ESCAPE:
2867 if ( this.menu.element.is( ":visible" ) ) {
2868 if ( !this.isMultiLine ) {
2869 this._value( this.term );
2871 this.close( event );
2872 // Different browsers have different default behavior for escape
2873 // Single press can mean undo or clear
2874 // Double press in IE means clear the whole form
2875 event.preventDefault();
2879 suppressKeyPressRepeat = true;
2880 // search timeout should be triggered before the input value is changed
2881 this._searchTimeout( event );
2885 keypress: function( event ) {
2886 if ( suppressKeyPress ) {
2887 suppressKeyPress = false;
2888 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
2889 event.preventDefault();
2893 if ( suppressKeyPressRepeat ) {
2897 // replicate some key handlers to allow them to repeat in Firefox and Opera
2898 var keyCode = $.ui.keyCode;
2899 switch ( event.keyCode ) {
2900 case keyCode.PAGE_UP:
2901 this._move( "previousPage", event );
2903 case keyCode.PAGE_DOWN:
2904 this._move( "nextPage", event );
2907 this._keyEvent( "previous", event );
2910 this._keyEvent( "next", event );
2914 input: function( event ) {
2915 if ( suppressInput ) {
2916 suppressInput = false;
2917 event.preventDefault();
2920 this._searchTimeout( event );
2923 this.selectedItem = null;
2924 this.previous = this._value();
2926 blur: function( event ) {
2927 if ( this.cancelBlur ) {
2928 delete this.cancelBlur;
2932 clearTimeout( this.searching );
2933 this.close( event );
2934 this._change( event );
2939 this.menu = $( "<ul>" )
2940 .addClass( "ui-autocomplete ui-front" )
2941 .appendTo( this._appendTo() )
2943 // disable ARIA support, the live region takes care of that
2947 .menu( "instance" );
2949 this._on( this.menu.element, {
2950 mousedown: function( event ) {
2951 // prevent moving focus out of the text field
2952 event.preventDefault();
2954 // IE doesn't prevent moving focus even with event.preventDefault()
2955 // so we set a flag to know when we should ignore the blur event
2956 this.cancelBlur = true;
2957 this._delay(function() {
2958 delete this.cancelBlur;
2961 // clicking on the scrollbar causes focus to shift to the body
2962 // but we can't detect a mouseup or a click immediately afterward
2963 // so we have to track the next mousedown and close the menu if
2964 // the user clicks somewhere outside of the autocomplete
2965 var menuElement = this.menu.element[ 0 ];
2966 if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
2967 this._delay(function() {
2969 this.document.one( "mousedown", function( event ) {
2970 if ( event.target !== that.element[ 0 ] &&
2971 event.target !== menuElement &&
2972 !$.contains( menuElement, event.target ) ) {
2979 menufocus: function( event, ui ) {
2982 // Prevent accidental activation of menu items in Firefox (#7024 #9118)
2983 if ( this.isNewMenu ) {
2984 this.isNewMenu = false;
2985 if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
2988 this.document.one( "mousemove", function() {
2989 $( event.target ).trigger( event.originalEvent );
2996 item = ui.item.data( "ui-autocomplete-item" );
2997 if ( false !== this._trigger( "focus", event, { item: item } ) ) {
2998 // use value to match what will end up in the input, if it was a key event
2999 if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
3000 this._value( item.value );
3004 // Announce the value in the liveRegion
3005 label = ui.item.attr( "aria-label" ) || item.value;
3006 if ( label && $.trim( label ).length ) {
3007 this.liveRegion.children().hide();
3008 $( "<div>" ).text( label ).appendTo( this.liveRegion );
3011 menuselect: function( event, ui ) {
3012 var item = ui.item.data( "ui-autocomplete-item" ),
3013 previous = this.previous;
3015 // only trigger when focus was lost (click on menu)
3016 if ( this.element[ 0 ] !== this.document[ 0 ].activeElement ) {
3017 this.element.focus();
3018 this.previous = previous;
3019 // #6109 - IE triggers two focus events and the second
3020 // is asynchronous, so we need to reset the previous
3021 // term synchronously and asynchronously :-(
3022 this._delay(function() {
3023 this.previous = previous;
3024 this.selectedItem = item;
3028 if ( false !== this._trigger( "select", event, { item: item } ) ) {
3029 this._value( item.value );
3031 // reset the term after the select event
3032 // this allows custom select handling to work properly
3033 this.term = this._value();
3035 this.close( event );
3036 this.selectedItem = item;
3040 this.liveRegion = $( "<span>", {
3042 "aria-live": "assertive",
3043 "aria-relevant": "additions"
3045 .addClass( "ui-helper-hidden-accessible" )
3046 .appendTo( this.document[ 0 ].body );
3048 // turning off autocomplete prevents the browser from remembering the
3049 // value when navigating through history, so we re-enable autocomplete
3050 // if the page is unloaded before the widget is destroyed. #7790
3051 this._on( this.window, {
3052 beforeunload: function() {
3053 this.element.removeAttr( "autocomplete" );
3058 _destroy: function() {
3059 clearTimeout( this.searching );
3061 .removeClass( "ui-autocomplete-input" )
3062 .removeAttr( "autocomplete" );
3063 this.menu.element.remove();
3064 this.liveRegion.remove();
3067 _setOption: function( key, value ) {
3068 this._super( key, value );
3069 if ( key === "source" ) {
3072 if ( key === "appendTo" ) {
3073 this.menu.element.appendTo( this._appendTo() );
3075 if ( key === "disabled" && value && this.xhr ) {
3080 _appendTo: function() {
3081 var element = this.options.appendTo;
3084 element = element.jquery || element.nodeType ?
3086 this.document.find( element ).eq( 0 );
3089 if ( !element || !element[ 0 ] ) {
3090 element = this.element.closest( ".ui-front" );
3093 if ( !element.length ) {
3094 element = this.document[ 0 ].body;
3100 _initSource: function() {
3103 if ( $.isArray( this.options.source ) ) {
3104 array = this.options.source;
3105 this.source = function( request, response ) {
3106 response( $.ui.autocomplete.filter( array, request.term ) );
3108 } else if ( typeof this.options.source === "string" ) {
3109 url = this.options.source;
3110 this.source = function( request, response ) {
3118 success: function( data ) {
3127 this.source = this.options.source;
3131 _searchTimeout: function( event ) {
3132 clearTimeout( this.searching );
3133 this.searching = this._delay(function() {
3135 // Search if the value has changed, or if the user retypes the same value (see #7434)
3136 var equalValues = this.term === this._value(),
3137 menuVisible = this.menu.element.is( ":visible" ),
3138 modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
3140 if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) {
3141 this.selectedItem = null;
3142 this.search( null, event );
3144 }, this.options.delay );
3147 search: function( value, event ) {
3148 value = value != null ? value : this._value();
3150 // always save the actual value, not the one passed as an argument
3151 this.term = this._value();
3153 if ( value.length < this.options.minLength ) {
3154 return this.close( event );
3157 if ( this._trigger( "search", event ) === false ) {
3161 return this._search( value );
3164 _search: function( value ) {
3166 this.element.addClass( "ui-autocomplete-loading" );
3167 this.cancelSearch = false;
3169 this.source( { term: value }, this._response() );
3172 _response: function() {
3173 var index = ++this.requestIndex;
3175 return $.proxy(function( content ) {
3176 if ( index === this.requestIndex ) {
3177 this.__response( content );
3181 if ( !this.pending ) {
3182 this.element.removeClass( "ui-autocomplete-loading" );
3187 __response: function( content ) {
3189 content = this._normalize( content );
3191 this._trigger( "response", null, { content: content } );
3192 if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
3193 this._suggest( content );
3194 this._trigger( "open" );
3196 // use ._close() instead of .close() so we don't cancel future searches
3201 close: function( event ) {
3202 this.cancelSearch = true;
3203 this._close( event );
3206 _close: function( event ) {
3207 if ( this.menu.element.is( ":visible" ) ) {
3208 this.menu.element.hide();
3210 this.isNewMenu = true;
3211 this._trigger( "close", event );
3215 _change: function( event ) {
3216 if ( this.previous !== this._value() ) {
3217 this._trigger( "change", event, { item: this.selectedItem } );
3221 _normalize: function( items ) {
3222 // assume all items have the right format when the first item is complete
3223 if ( items.length && items[ 0 ].label && items[ 0 ].value ) {
3226 return $.map( items, function( item ) {
3227 if ( typeof item === "string" ) {
3233 return $.extend( {}, item, {
3234 label: item.label || item.value,
3235 value: item.value || item.label
3240 _suggest: function( items ) {
3241 var ul = this.menu.element.empty();
3242 this._renderMenu( ul, items );
3243 this.isNewMenu = true;
3244 this.menu.refresh();
3246 // size and position menu
3249 ul.position( $.extend({
3251 }, this.options.position ) );
3253 if ( this.options.autoFocus ) {
3258 _resizeMenu: function() {
3259 var ul = this.menu.element;
3260 ul.outerWidth( Math.max(
3261 // Firefox wraps long text (possibly a rounding bug)
3262 // so we add 1px to avoid the wrapping (#7513)
3263 ul.width( "" ).outerWidth() + 1,
3264 this.element.outerWidth()
3268 _renderMenu: function( ul, items ) {
3270 $.each( items, function( index, item ) {
3271 that._renderItemData( ul, item );
3275 _renderItemData: function( ul, item ) {
3276 return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
3279 _renderItem: function( ul, item ) {
3280 return $( "<li>" ).text( item.label ).appendTo( ul );
3283 _move: function( direction, event ) {
3284 if ( !this.menu.element.is( ":visible" ) ) {
3285 this.search( null, event );
3288 if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
3289 this.menu.isLastItem() && /^next/.test( direction ) ) {
3291 if ( !this.isMultiLine ) {
3292 this._value( this.term );
3298 this.menu[ direction ]( event );
3301 widget: function() {
3302 return this.menu.element;
3305 _value: function() {
3306 return this.valueMethod.apply( this.element, arguments );
3309 _keyEvent: function( keyEvent, event ) {
3310 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
3311 this._move( keyEvent, event );
3313 // prevents moving cursor to beginning/end of the text field in some browsers
3314 event.preventDefault();
3319 $.extend( $.ui.autocomplete, {
3320 escapeRegex: function( value ) {
3321 return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
3323 filter: function( array, term ) {
3324 var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" );
3325 return $.grep( array, function( value ) {
3326 return matcher.test( value.label || value.value || value );
3331 // live region extension, adding a `messages` option
3332 // NOTE: This is an experimental API. We are still investigating
3333 // a full solution for string manipulation and internationalization.
3334 $.widget( "ui.autocomplete", $.ui.autocomplete, {
3337 noResults: "No search results.",
3338 results: function( amount ) {
3339 return amount + ( amount > 1 ? " results are" : " result is" ) +
3340 " available, use up and down arrow keys to navigate.";
3345 __response: function( content ) {
3347 this._superApply( arguments );
3348 if ( this.options.disabled || this.cancelSearch ) {
3351 if ( content && content.length ) {
3352 message = this.options.messages.results( content.length );
3354 message = this.options.messages.noResults;
3356 this.liveRegion.children().hide();
3357 $( "<div>" ).text( message ).appendTo( this.liveRegion );
3361 var autocomplete = $.ui.autocomplete;
3365 * jQuery UI Button 1.11.2
3366 * http://jqueryui.com
3368 * Copyright 2014 jQuery Foundation and other contributors
3369 * Released under the MIT license.
3370 * http://jquery.org/license
3372 * http://api.jqueryui.com/button/
3377 baseClasses = "ui-button ui-widget ui-state-default ui-corner-all",
3378 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",
3379 formResetHandler = function() {
3380 var form = $( this );
3381 setTimeout(function() {
3382 form.find( ":ui-button" ).button( "refresh" );
3385 radioGroup = function( radio ) {
3386 var name = radio.name,
3390 name = name.replace( /'/g, "\\'" );
3392 radios = $( form ).find( "[name='" + name + "'][type=radio]" );
3394 radios = $( "[name='" + name + "'][type=radio]", radio.ownerDocument )
3395 .filter(function() {
3403 $.widget( "ui.button", {
3405 defaultElement: "<button>",
3415 _create: function() {
3416 this.element.closest( "form" )
3417 .unbind( "reset" + this.eventNamespace )
3418 .bind( "reset" + this.eventNamespace, formResetHandler );
3420 if ( typeof this.options.disabled !== "boolean" ) {
3421 this.options.disabled = !!this.element.prop( "disabled" );
3423 this.element.prop( "disabled", this.options.disabled );
3426 this._determineButtonType();
3427 this.hasTitle = !!this.buttonElement.attr( "title" );
3430 options = this.options,
3431 toggleButton = this.type === "checkbox" || this.type === "radio",
3432 activeClass = !toggleButton ? "ui-state-active" : "";
3434 if ( options.label === null ) {
3435 options.label = (this.type === "input" ? this.buttonElement.val() : this.buttonElement.html());
3438 this._hoverable( this.buttonElement );
3441 .addClass( baseClasses )
3442 .attr( "role", "button" )
3443 .bind( "mouseenter" + this.eventNamespace, function() {
3444 if ( options.disabled ) {
3447 if ( this === lastActive ) {
3448 $( this ).addClass( "ui-state-active" );
3451 .bind( "mouseleave" + this.eventNamespace, function() {
3452 if ( options.disabled ) {
3455 $( this ).removeClass( activeClass );
3457 .bind( "click" + this.eventNamespace, function( event ) {
3458 if ( options.disabled ) {
3459 event.preventDefault();
3460 event.stopImmediatePropagation();
3464 // Can't use _focusable() because the element that receives focus
3465 // and the element that gets the ui-state-focus class are different
3468 this.buttonElement.addClass( "ui-state-focus" );
3471 this.buttonElement.removeClass( "ui-state-focus" );
3475 if ( toggleButton ) {
3476 this.element.bind( "change" + this.eventNamespace, function() {
3481 if ( this.type === "checkbox" ) {
3482 this.buttonElement.bind( "click" + this.eventNamespace, function() {
3483 if ( options.disabled ) {
3487 } else if ( this.type === "radio" ) {
3488 this.buttonElement.bind( "click" + this.eventNamespace, function() {
3489 if ( options.disabled ) {
3492 $( this ).addClass( "ui-state-active" );
3493 that.buttonElement.attr( "aria-pressed", "true" );
3495 var radio = that.element[ 0 ];
3499 return $( this ).button( "widget" )[ 0 ];
3501 .removeClass( "ui-state-active" )
3502 .attr( "aria-pressed", "false" );
3506 .bind( "mousedown" + this.eventNamespace, function() {
3507 if ( options.disabled ) {
3510 $( this ).addClass( "ui-state-active" );
3512 that.document.one( "mouseup", function() {
3516 .bind( "mouseup" + this.eventNamespace, function() {
3517 if ( options.disabled ) {
3520 $( this ).removeClass( "ui-state-active" );
3522 .bind( "keydown" + this.eventNamespace, function(event) {
3523 if ( options.disabled ) {
3526 if ( event.keyCode === $.ui.keyCode.SPACE || event.keyCode === $.ui.keyCode.ENTER ) {
3527 $( this ).addClass( "ui-state-active" );
3530 // see #8559, we bind to blur here in case the button element loses
3531 // focus between keydown and keyup, it would be left in an "active" state
3532 .bind( "keyup" + this.eventNamespace + " blur" + this.eventNamespace, function() {
3533 $( this ).removeClass( "ui-state-active" );
3536 if ( this.buttonElement.is("a") ) {
3537 this.buttonElement.keyup(function(event) {
3538 if ( event.keyCode === $.ui.keyCode.SPACE ) {
3539 // TODO pass through original event correctly (just as 2nd argument doesn't work)
3546 this._setOption( "disabled", options.disabled );
3547 this._resetButton();
3550 _determineButtonType: function() {
3551 var ancestor, labelSelector, checked;
3553 if ( this.element.is("[type=checkbox]") ) {
3554 this.type = "checkbox";
3555 } else if ( this.element.is("[type=radio]") ) {
3556 this.type = "radio";
3557 } else if ( this.element.is("input") ) {
3558 this.type = "input";
3560 this.type = "button";
3563 if ( this.type === "checkbox" || this.type === "radio" ) {
3564 // we don't search against the document in case the element
3565 // is disconnected from the DOM
3566 ancestor = this.element.parents().last();
3567 labelSelector = "label[for='" + this.element.attr("id") + "']";
3568 this.buttonElement = ancestor.find( labelSelector );
3569 if ( !this.buttonElement.length ) {
3570 ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings();
3571 this.buttonElement = ancestor.filter( labelSelector );
3572 if ( !this.buttonElement.length ) {
3573 this.buttonElement = ancestor.find( labelSelector );
3576 this.element.addClass( "ui-helper-hidden-accessible" );
3578 checked = this.element.is( ":checked" );
3580 this.buttonElement.addClass( "ui-state-active" );
3582 this.buttonElement.prop( "aria-pressed", checked );
3584 this.buttonElement = this.element;
3588 widget: function() {
3589 return this.buttonElement;
3592 _destroy: function() {
3594 .removeClass( "ui-helper-hidden-accessible" );
3596 .removeClass( baseClasses + " ui-state-active " + typeClasses )
3597 .removeAttr( "role" )
3598 .removeAttr( "aria-pressed" )
3599 .html( this.buttonElement.find(".ui-button-text").html() );
3601 if ( !this.hasTitle ) {
3602 this.buttonElement.removeAttr( "title" );
3606 _setOption: function( key, value ) {
3607 this._super( key, value );
3608 if ( key === "disabled" ) {
3609 this.widget().toggleClass( "ui-state-disabled", !!value );
3610 this.element.prop( "disabled", !!value );
3612 if ( this.type === "checkbox" || this.type === "radio" ) {
3613 this.buttonElement.removeClass( "ui-state-focus" );
3615 this.buttonElement.removeClass( "ui-state-focus ui-state-active" );
3620 this._resetButton();
3623 refresh: function() {
3625 var isDisabled = this.element.is( "input, button" ) ? this.element.is( ":disabled" ) : this.element.hasClass( "ui-button-disabled" );
3627 if ( isDisabled !== this.options.disabled ) {
3628 this._setOption( "disabled", isDisabled );
3630 if ( this.type === "radio" ) {
3631 radioGroup( this.element[0] ).each(function() {
3632 if ( $( this ).is( ":checked" ) ) {
3633 $( this ).button( "widget" )
3634 .addClass( "ui-state-active" )
3635 .attr( "aria-pressed", "true" );
3637 $( this ).button( "widget" )
3638 .removeClass( "ui-state-active" )
3639 .attr( "aria-pressed", "false" );
3642 } else if ( this.type === "checkbox" ) {
3643 if ( this.element.is( ":checked" ) ) {
3645 .addClass( "ui-state-active" )
3646 .attr( "aria-pressed", "true" );
3649 .removeClass( "ui-state-active" )
3650 .attr( "aria-pressed", "false" );
3655 _resetButton: function() {
3656 if ( this.type === "input" ) {
3657 if ( this.options.label ) {
3658 this.element.val( this.options.label );
3662 var buttonElement = this.buttonElement.removeClass( typeClasses ),
3663 buttonText = $( "<span></span>", this.document[0] )
3664 .addClass( "ui-button-text" )
3665 .html( this.options.label )
3666 .appendTo( buttonElement.empty() )
3668 icons = this.options.icons,
3669 multipleIcons = icons.primary && icons.secondary,
3672 if ( icons.primary || icons.secondary ) {
3673 if ( this.options.text ) {
3674 buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) );
3677 if ( icons.primary ) {
3678 buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" );
3681 if ( icons.secondary ) {
3682 buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" );
3685 if ( !this.options.text ) {
3686 buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" );
3688 if ( !this.hasTitle ) {
3689 buttonElement.attr( "title", $.trim( buttonText ) );
3693 buttonClasses.push( "ui-button-text-only" );
3695 buttonElement.addClass( buttonClasses.join( " " ) );
3699 $.widget( "ui.buttonset", {
3702 items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)"
3705 _create: function() {
3706 this.element.addClass( "ui-buttonset" );
3713 _setOption: function( key, value ) {
3714 if ( key === "disabled" ) {
3715 this.buttons.button( "option", key, value );
3718 this._super( key, value );
3721 refresh: function() {
3722 var rtl = this.element.css( "direction" ) === "rtl",
3723 allButtons = this.element.find( this.options.items ),
3724 existingButtons = allButtons.filter( ":ui-button" );
3726 // Initialize new buttons
3727 allButtons.not( ":ui-button" ).button();
3729 // Refresh existing buttons
3730 existingButtons.button( "refresh" );
3732 this.buttons = allButtons
3734 return $( this ).button( "widget" )[ 0 ];
3736 .removeClass( "ui-corner-all ui-corner-left ui-corner-right" )
3738 .addClass( rtl ? "ui-corner-right" : "ui-corner-left" )
3741 .addClass( rtl ? "ui-corner-left" : "ui-corner-right" )
3746 _destroy: function() {
3747 this.element.removeClass( "ui-buttonset" );
3750 return $( this ).button( "widget" )[ 0 ];
3752 .removeClass( "ui-corner-left ui-corner-right" )
3754 .button( "destroy" );
3758 var button = $.ui.button;
3762 * jQuery UI Datepicker 1.11.2
3763 * http://jqueryui.com
3765 * Copyright 2014 jQuery Foundation and other contributors
3766 * Released under the MIT license.
3767 * http://jquery.org/license
3769 * http://api.jqueryui.com/datepicker/
3773 $.extend($.ui, { datepicker: { version: "1.11.2" } });
3775 var datepicker_instActive;
3777 function datepicker_getZindex( elem ) {
3778 var position, value;
3779 while ( elem.length && elem[ 0 ] !== document ) {
3780 // Ignore z-index if position is set to a value where z-index is ignored by the browser
3781 // This makes behavior of this function consistent across browsers
3782 // WebKit always returns auto if the element is positioned
3783 position = elem.css( "position" );
3784 if ( position === "absolute" || position === "relative" || position === "fixed" ) {
3785 // IE returns 0 when zIndex is not specified
3786 // other browsers return a string
3787 // we ignore the case of nested elements with an explicit value of 0
3788 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
3789 value = parseInt( elem.css( "zIndex" ), 10 );
3790 if ( !isNaN( value ) && value !== 0 ) {
3794 elem = elem.parent();
3799 /* Date picker manager.
3800 Use the singleton instance of this class, $.datepicker, to interact with the date picker.
3801 Settings for (groups of) date pickers are maintained in an instance object,
3802 allowing multiple different settings on the same page. */
3804 function Datepicker() {
3805 this._curInst = null; // The current instance in use
3806 this._keyEvent = false; // If the last event was a key event
3807 this._disabledInputs = []; // List of date picker inputs that have been disabled
3808 this._datepickerShowing = false; // True if the popup picker is showing , false if not
3809 this._inDialog = false; // True if showing within a "dialog", false if not
3810 this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
3811 this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
3812 this._appendClass = "ui-datepicker-append"; // The name of the append marker class
3813 this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
3814 this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
3815 this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
3816 this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
3817 this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
3818 this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
3819 this.regional = []; // Available regional settings, indexed by language code
3820 this.regional[""] = { // Default regional settings
3821 closeText: "Done", // Display text for close link
3822 prevText: "Prev", // Display text for previous month link
3823 nextText: "Next", // Display text for next month link
3824 currentText: "Today", // Display text for current month link
3825 monthNames: ["January","February","March","April","May","June",
3826 "July","August","September","October","November","December"], // Names of months for drop-down and formatting
3827 monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting
3828 dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting
3829 dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting
3830 dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday
3831 weekHeader: "Wk", // Column header for week of the year
3832 dateFormat: "mm/dd/yy", // See format options on parseDate
3833 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
3834 isRTL: false, // True if right-to-left language, false if left-to-right
3835 showMonthAfterYear: false, // True if the year select precedes month, false for month then year
3836 yearSuffix: "" // Additional text to append to the year in the month headers
3838 this._defaults = { // Global defaults for all the date picker instances
3839 showOn: "focus", // "focus" for popup on focus,
3840 // "button" for trigger button, or "both" for either
3841 showAnim: "fadeIn", // Name of jQuery animation for popup
3842 showOptions: {}, // Options for enhanced animations
3843 defaultDate: null, // Used when field is blank: actual date,
3844 // +/-number for offset from today, null for today
3845 appendText: "", // Display text following the input box, e.g. showing the format
3846 buttonText: "...", // Text for trigger button
3847 buttonImage: "", // URL for trigger button image
3848 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
3849 hideIfNoPrevNext: false, // True to hide next/previous month links
3850 // if not applicable, false to just disable them
3851 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
3852 gotoCurrent: false, // True if today link goes back to current selection instead
3853 changeMonth: false, // True if month can be selected directly, false if only prev/next
3854 changeYear: false, // True if year can be selected directly, false if only prev/next
3855 yearRange: "c-10:c+10", // Range of years to display in drop-down,
3856 // either relative to today's year (-nn:+nn), relative to currently displayed year
3857 // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
3858 showOtherMonths: false, // True to show dates in other months, false to leave blank
3859 selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
3860 showWeek: false, // True to show week of the year, false to not show it
3861 calculateWeek: this.iso8601Week, // How to calculate the week of the year,
3862 // takes a Date and returns the number of the week for it
3863 shortYearCutoff: "+10", // Short year values < this are in the current century,
3864 // > this are in the previous century,
3865 // string value starting with "+" for current year + value
3866 minDate: null, // The earliest selectable date, or null for no limit
3867 maxDate: null, // The latest selectable date, or null for no limit
3868 duration: "fast", // Duration of display/closure
3869 beforeShowDay: null, // Function that takes a date and returns an array with
3870 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
3871 // [2] = cell title (optional), e.g. $.datepicker.noWeekends
3872 beforeShow: null, // Function that takes an input field and
3873 // returns a set of custom settings for the date picker
3874 onSelect: null, // Define a callback function when a date is selected
3875 onChangeMonthYear: null, // Define a callback function when the month or year is changed
3876 onClose: null, // Define a callback function when the datepicker is closed
3877 numberOfMonths: 1, // Number of months to show at a time
3878 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
3879 stepMonths: 1, // Number of months to step back/forward
3880 stepBigMonths: 12, // Number of months to step back/forward for the big links
3881 altField: "", // Selector for an alternate field to store selected dates into
3882 altFormat: "", // The date format to use for the alternate field
3883 constrainInput: true, // The input is constrained by the current date format
3884 showButtonPanel: false, // True to show button panel, false to not show it
3885 autoSize: false, // True to size the input for the date format, false to leave as is
3886 disabled: false // The initial disabled state
3888 $.extend(this._defaults, this.regional[""]);
3889 this.regional.en = $.extend( true, {}, this.regional[ "" ]);
3890 this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en );
3891 this.dpDiv = datepicker_bindHover($("<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"));
3894 $.extend(Datepicker.prototype, {
3895 /* Class name added to elements to indicate already configured with a date picker. */
3896 markerClassName: "hasDatepicker",
3898 //Keep track of the maximum number of rows displayed (see #7043)
3901 // TODO rename to "widget" when switching to widget factory
3902 _widgetDatepicker: function() {
3906 /* Override the default settings for all instances of the date picker.
3907 * @param settings object - the new settings to use as defaults (anonymous object)
3908 * @return the manager object
3910 setDefaults: function(settings) {
3911 datepicker_extendRemove(this._defaults, settings || {});
3915 /* Attach the date picker to a jQuery selection.
3916 * @param target element - the target input field or division or span
3917 * @param settings object - the new settings to use for this date picker instance (anonymous)
3919 _attachDatepicker: function(target, settings) {
3920 var nodeName, inline, inst;
3921 nodeName = target.nodeName.toLowerCase();
3922 inline = (nodeName === "div" || nodeName === "span");
3925 target.id = "dp" + this.uuid;
3927 inst = this._newInst($(target), inline);
3928 inst.settings = $.extend({}, settings || {});
3929 if (nodeName === "input") {
3930 this._connectDatepicker(target, inst);
3931 } else if (inline) {
3932 this._inlineDatepicker(target, inst);
3936 /* Create a new instance object. */
3937 _newInst: function(target, inline) {
3938 var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars
3939 return {id: id, input: target, // associated target
3940 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
3941 drawMonth: 0, drawYear: 0, // month being drawn
3942 inline: inline, // is datepicker inline or not
3943 dpDiv: (!inline ? this.dpDiv : // presentation div
3944 datepicker_bindHover($("<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))};
3947 /* Attach the date picker to an input field. */
3948 _connectDatepicker: function(target, inst) {
3949 var input = $(target);
3950 inst.append = $([]);
3951 inst.trigger = $([]);
3952 if (input.hasClass(this.markerClassName)) {
3955 this._attachments(input, inst);
3956 input.addClass(this.markerClassName).keydown(this._doKeyDown).
3957 keypress(this._doKeyPress).keyup(this._doKeyUp);
3958 this._autoSize(inst);
3959 $.data(target, "datepicker", inst);
3960 //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
3961 if( inst.settings.disabled ) {
3962 this._disableDatepicker( target );
3966 /* Make attachments based on settings. */
3967 _attachments: function(input, inst) {
3968 var showOn, buttonText, buttonImage,
3969 appendText = this._get(inst, "appendText"),
3970 isRTL = this._get(inst, "isRTL");
3973 inst.append.remove();
3976 inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>");
3977 input[isRTL ? "before" : "after"](inst.append);
3980 input.unbind("focus", this._showDatepicker);
3983 inst.trigger.remove();
3986 showOn = this._get(inst, "showOn");
3987 if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field
3988 input.focus(this._showDatepicker);
3990 if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked
3991 buttonText = this._get(inst, "buttonText");
3992 buttonImage = this._get(inst, "buttonImage");
3993 inst.trigger = $(this._get(inst, "buttonImageOnly") ?
3994 $("<img/>").addClass(this._triggerClass).
3995 attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
3996 $("<button type='button'></button>").addClass(this._triggerClass).
3997 html(!buttonImage ? buttonText : $("<img/>").attr(
3998 { src:buttonImage, alt:buttonText, title:buttonText })));
3999 input[isRTL ? "before" : "after"](inst.trigger);
4000 inst.trigger.click(function() {
4001 if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) {
4002 $.datepicker._hideDatepicker();
4003 } else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) {
4004 $.datepicker._hideDatepicker();
4005 $.datepicker._showDatepicker(input[0]);
4007 $.datepicker._showDatepicker(input[0]);
4014 /* Apply the maximum length for the date format. */
4015 _autoSize: function(inst) {
4016 if (this._get(inst, "autoSize") && !inst.inline) {
4017 var findMax, max, maxI, i,
4018 date = new Date(2009, 12 - 1, 20), // Ensure double digits
4019 dateFormat = this._get(inst, "dateFormat");
4021 if (dateFormat.match(/[DM]/)) {
4022 findMax = function(names) {
4025 for (i = 0; i < names.length; i++) {
4026 if (names[i].length > max) {
4027 max = names[i].length;
4033 date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
4034 "monthNames" : "monthNamesShort"))));
4035 date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
4036 "dayNames" : "dayNamesShort"))) + 20 - date.getDay());
4038 inst.input.attr("size", this._formatDate(inst, date).length);
4042 /* Attach an inline date picker to a div. */
4043 _inlineDatepicker: function(target, inst) {
4044 var divSpan = $(target);
4045 if (divSpan.hasClass(this.markerClassName)) {
4048 divSpan.addClass(this.markerClassName).append(inst.dpDiv);
4049 $.data(target, "datepicker", inst);
4050 this._setDate(inst, this._getDefaultDate(inst), true);
4051 this._updateDatepicker(inst);
4052 this._updateAlternate(inst);
4053 //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
4054 if( inst.settings.disabled ) {
4055 this._disableDatepicker( target );
4057 // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
4058 // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
4059 inst.dpDiv.css( "display", "block" );
4062 /* Pop-up the date picker in a "dialog" box.
4063 * @param input element - ignored
4064 * @param date string or Date - the initial date to display
4065 * @param onSelect function - the function to call when a date is selected
4066 * @param settings object - update the dialog date picker instance's settings (anonymous object)
4067 * @param pos int[2] - coordinates for the dialog's position within the screen or
4068 * event - with x/y coordinates or
4069 * leave empty for default (screen centre)
4070 * @return the manager object
4072 _dialogDatepicker: function(input, date, onSelect, settings, pos) {
4073 var id, browserWidth, browserHeight, scrollX, scrollY,
4074 inst = this._dialogInst; // internal instance
4078 id = "dp" + this.uuid;
4079 this._dialogInput = $("<input type='text' id='" + id +
4080 "' style='position: absolute; top: -100px; width: 0px;'/>");
4081 this._dialogInput.keydown(this._doKeyDown);
4082 $("body").append(this._dialogInput);
4083 inst = this._dialogInst = this._newInst(this._dialogInput, false);
4085 $.data(this._dialogInput[0], "datepicker", inst);
4087 datepicker_extendRemove(inst.settings, settings || {});
4088 date = (date && date.constructor === Date ? this._formatDate(inst, date) : date);
4089 this._dialogInput.val(date);
4091 this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
4093 browserWidth = document.documentElement.clientWidth;
4094 browserHeight = document.documentElement.clientHeight;
4095 scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
4096 scrollY = document.documentElement.scrollTop || document.body.scrollTop;
4097 this._pos = // should use actual width/height below
4098 [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
4101 // move input on screen for focus, but hidden behind dialog
4102 this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px");
4103 inst.settings.onSelect = onSelect;
4104 this._inDialog = true;
4105 this.dpDiv.addClass(this._dialogClass);
4106 this._showDatepicker(this._dialogInput[0]);
4108 $.blockUI(this.dpDiv);
4110 $.data(this._dialogInput[0], "datepicker", inst);
4114 /* Detach a datepicker from its control.
4115 * @param target element - the target input field or division or span
4117 _destroyDatepicker: function(target) {
4119 $target = $(target),
4120 inst = $.data(target, "datepicker");
4122 if (!$target.hasClass(this.markerClassName)) {
4126 nodeName = target.nodeName.toLowerCase();
4127 $.removeData(target, "datepicker");
4128 if (nodeName === "input") {
4129 inst.append.remove();
4130 inst.trigger.remove();
4131 $target.removeClass(this.markerClassName).
4132 unbind("focus", this._showDatepicker).
4133 unbind("keydown", this._doKeyDown).
4134 unbind("keypress", this._doKeyPress).
4135 unbind("keyup", this._doKeyUp);
4136 } else if (nodeName === "div" || nodeName === "span") {
4137 $target.removeClass(this.markerClassName).empty();
4141 /* Enable the date picker to a jQuery selection.
4142 * @param target element - the target input field or division or span
4144 _enableDatepicker: function(target) {
4145 var nodeName, inline,
4146 $target = $(target),
4147 inst = $.data(target, "datepicker");
4149 if (!$target.hasClass(this.markerClassName)) {
4153 nodeName = target.nodeName.toLowerCase();
4154 if (nodeName === "input") {
4155 target.disabled = false;
4156 inst.trigger.filter("button").
4157 each(function() { this.disabled = false; }).end().
4158 filter("img").css({opacity: "1.0", cursor: ""});
4159 } else if (nodeName === "div" || nodeName === "span") {
4160 inline = $target.children("." + this._inlineClass);
4161 inline.children().removeClass("ui-state-disabled");
4162 inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
4163 prop("disabled", false);
4165 this._disabledInputs = $.map(this._disabledInputs,
4166 function(value) { return (value === target ? null : value); }); // delete entry
4169 /* Disable the date picker to a jQuery selection.
4170 * @param target element - the target input field or division or span
4172 _disableDatepicker: function(target) {
4173 var nodeName, inline,
4174 $target = $(target),
4175 inst = $.data(target, "datepicker");
4177 if (!$target.hasClass(this.markerClassName)) {
4181 nodeName = target.nodeName.toLowerCase();
4182 if (nodeName === "input") {
4183 target.disabled = true;
4184 inst.trigger.filter("button").
4185 each(function() { this.disabled = true; }).end().
4186 filter("img").css({opacity: "0.5", cursor: "default"});
4187 } else if (nodeName === "div" || nodeName === "span") {
4188 inline = $target.children("." + this._inlineClass);
4189 inline.children().addClass("ui-state-disabled");
4190 inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
4191 prop("disabled", true);
4193 this._disabledInputs = $.map(this._disabledInputs,
4194 function(value) { return (value === target ? null : value); }); // delete entry
4195 this._disabledInputs[this._disabledInputs.length] = target;
4198 /* Is the first field in a jQuery collection disabled as a datepicker?
4199 * @param target element - the target input field or division or span
4200 * @return boolean - true if disabled, false if enabled
4202 _isDisabledDatepicker: function(target) {
4206 for (var i = 0; i < this._disabledInputs.length; i++) {
4207 if (this._disabledInputs[i] === target) {
4214 /* Retrieve the instance data for the target control.
4215 * @param target element - the target input field or division or span
4216 * @return object - the associated instance data
4217 * @throws error if a jQuery problem getting data
4219 _getInst: function(target) {
4221 return $.data(target, "datepicker");
4224 throw "Missing instance data for this datepicker";
4228 /* Update or retrieve the settings for a date picker attached to an input field or division.
4229 * @param target element - the target input field or division or span
4230 * @param name object - the new settings to update or
4231 * string - the name of the setting to change or retrieve,
4232 * when retrieving also "all" for all instance settings or
4233 * "defaults" for all global defaults
4234 * @param value any - the new value for the setting
4235 * (omit if above is an object or to retrieve a value)
4237 _optionDatepicker: function(target, name, value) {
4238 var settings, date, minDate, maxDate,
4239 inst = this._getInst(target);
4241 if (arguments.length === 2 && typeof name === "string") {
4242 return (name === "defaults" ? $.extend({}, $.datepicker._defaults) :
4243 (inst ? (name === "all" ? $.extend({}, inst.settings) :
4244 this._get(inst, name)) : null));
4247 settings = name || {};
4248 if (typeof name === "string") {
4250 settings[name] = value;
4254 if (this._curInst === inst) {
4255 this._hideDatepicker();
4258 date = this._getDateDatepicker(target, true);
4259 minDate = this._getMinMaxDate(inst, "min");
4260 maxDate = this._getMinMaxDate(inst, "max");
4261 datepicker_extendRemove(inst.settings, settings);
4262 // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
4263 if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) {
4264 inst.settings.minDate = this._formatDate(inst, minDate);
4266 if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) {
4267 inst.settings.maxDate = this._formatDate(inst, maxDate);
4269 if ( "disabled" in settings ) {
4270 if ( settings.disabled ) {
4271 this._disableDatepicker(target);
4273 this._enableDatepicker(target);
4276 this._attachments($(target), inst);
4277 this._autoSize(inst);
4278 this._setDate(inst, date);
4279 this._updateAlternate(inst);
4280 this._updateDatepicker(inst);
4284 // change method deprecated
4285 _changeDatepicker: function(target, name, value) {
4286 this._optionDatepicker(target, name, value);
4289 /* Redraw the date picker attached to an input field or division.
4290 * @param target element - the target input field or division or span
4292 _refreshDatepicker: function(target) {
4293 var inst = this._getInst(target);
4295 this._updateDatepicker(inst);
4299 /* Set the dates for a jQuery selection.
4300 * @param target element - the target input field or division or span
4301 * @param date Date - the new date
4303 _setDateDatepicker: function(target, date) {
4304 var inst = this._getInst(target);
4306 this._setDate(inst, date);
4307 this._updateDatepicker(inst);
4308 this._updateAlternate(inst);
4312 /* Get the date(s) for the first entry in a jQuery selection.
4313 * @param target element - the target input field or division or span
4314 * @param noDefault boolean - true if no default date is to be used
4315 * @return Date - the current date
4317 _getDateDatepicker: function(target, noDefault) {
4318 var inst = this._getInst(target);
4319 if (inst && !inst.inline) {
4320 this._setDateFromField(inst, noDefault);
4322 return (inst ? this._getDate(inst) : null);
4325 /* Handle keystrokes. */
4326 _doKeyDown: function(event) {
4327 var onSelect, dateStr, sel,
4328 inst = $.datepicker._getInst(event.target),
4330 isRTL = inst.dpDiv.is(".ui-datepicker-rtl");
4332 inst._keyEvent = true;
4333 if ($.datepicker._datepickerShowing) {
4334 switch (event.keyCode) {
4335 case 9: $.datepicker._hideDatepicker();
4337 break; // hide on tab out
4338 case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." +
4339 $.datepicker._currentClass + ")", inst.dpDiv);
4341 $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
4344 onSelect = $.datepicker._get(inst, "onSelect");
4346 dateStr = $.datepicker._formatDate(inst);
4348 // trigger custom callback
4349 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);
4351 $.datepicker._hideDatepicker();
4354 return false; // don't submit the form
4355 case 27: $.datepicker._hideDatepicker();
4356 break; // hide on escape
4357 case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
4358 -$.datepicker._get(inst, "stepBigMonths") :
4359 -$.datepicker._get(inst, "stepMonths")), "M");
4360 break; // previous month/year on page up/+ ctrl
4361 case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
4362 +$.datepicker._get(inst, "stepBigMonths") :
4363 +$.datepicker._get(inst, "stepMonths")), "M");
4364 break; // next month/year on page down/+ ctrl
4365 case 35: if (event.ctrlKey || event.metaKey) {
4366 $.datepicker._clearDate(event.target);
4368 handled = event.ctrlKey || event.metaKey;
4369 break; // clear on ctrl or command +end
4370 case 36: if (event.ctrlKey || event.metaKey) {
4371 $.datepicker._gotoToday(event.target);
4373 handled = event.ctrlKey || event.metaKey;
4374 break; // current on ctrl or command +home
4375 case 37: if (event.ctrlKey || event.metaKey) {
4376 $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D");
4378 handled = event.ctrlKey || event.metaKey;
4379 // -1 day on ctrl or command +left
4380 if (event.originalEvent.altKey) {
4381 $.datepicker._adjustDate(event.target, (event.ctrlKey ?
4382 -$.datepicker._get(inst, "stepBigMonths") :
4383 -$.datepicker._get(inst, "stepMonths")), "M");
4385 // next month/year on alt +left on Mac
4387 case 38: if (event.ctrlKey || event.metaKey) {
4388 $.datepicker._adjustDate(event.target, -7, "D");
4390 handled = event.ctrlKey || event.metaKey;
4391 break; // -1 week on ctrl or command +up
4392 case 39: if (event.ctrlKey || event.metaKey) {
4393 $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D");
4395 handled = event.ctrlKey || event.metaKey;
4396 // +1 day on ctrl or command +right
4397 if (event.originalEvent.altKey) {
4398 $.datepicker._adjustDate(event.target, (event.ctrlKey ?
4399 +$.datepicker._get(inst, "stepBigMonths") :
4400 +$.datepicker._get(inst, "stepMonths")), "M");
4402 // next month/year on alt +right
4404 case 40: if (event.ctrlKey || event.metaKey) {
4405 $.datepicker._adjustDate(event.target, +7, "D");
4407 handled = event.ctrlKey || event.metaKey;
4408 break; // +1 week on ctrl or command +down
4409 default: handled = false;
4411 } else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home
4412 $.datepicker._showDatepicker(this);
4418 event.preventDefault();
4419 event.stopPropagation();
4423 /* Filter entered characters - based on date format. */
4424 _doKeyPress: function(event) {
4426 inst = $.datepicker._getInst(event.target);
4428 if ($.datepicker._get(inst, "constrainInput")) {
4429 chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat"));
4430 chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode);
4431 return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1);
4435 /* Synchronise manual entry and field/alternate field. */
4436 _doKeyUp: function(event) {
4438 inst = $.datepicker._getInst(event.target);
4440 if (inst.input.val() !== inst.lastVal) {
4442 date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
4443 (inst.input ? inst.input.val() : null),
4444 $.datepicker._getFormatConfig(inst));
4446 if (date) { // only if valid
4447 $.datepicker._setDateFromField(inst);
4448 $.datepicker._updateAlternate(inst);
4449 $.datepicker._updateDatepicker(inst);
4458 /* Pop-up the date picker for a given input field.
4459 * If false returned from beforeShow event handler do not show.
4460 * @param input element - the input field attached to the date picker or
4461 * event - if triggered by focus
4463 _showDatepicker: function(input) {
4464 input = input.target || input;
4465 if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger
4466 input = $("input", input.parentNode)[0];
4469 if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here
4473 var inst, beforeShow, beforeShowSettings, isFixed,
4474 offset, showAnim, duration;
4476 inst = $.datepicker._getInst(input);
4477 if ($.datepicker._curInst && $.datepicker._curInst !== inst) {
4478 $.datepicker._curInst.dpDiv.stop(true, true);
4479 if ( inst && $.datepicker._datepickerShowing ) {
4480 $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );
4484 beforeShow = $.datepicker._get(inst, "beforeShow");
4485 beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
4486 if(beforeShowSettings === false){
4489 datepicker_extendRemove(inst.settings, beforeShowSettings);
4491 inst.lastVal = null;
4492 $.datepicker._lastInput = input;
4493 $.datepicker._setDateFromField(inst);
4495 if ($.datepicker._inDialog) { // hide cursor
4498 if (!$.datepicker._pos) { // position below input
4499 $.datepicker._pos = $.datepicker._findPos(input);
4500 $.datepicker._pos[1] += input.offsetHeight; // add the height
4504 $(input).parents().each(function() {
4505 isFixed |= $(this).css("position") === "fixed";
4509 offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
4510 $.datepicker._pos = null;
4511 //to avoid flashes on Firefox
4513 // determine sizing offscreen
4514 inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"});
4515 $.datepicker._updateDatepicker(inst);
4516 // fix width for dynamic number of date pickers
4517 // and adjust position before showing
4518 offset = $.datepicker._checkOffset(inst, offset, isFixed);
4519 inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
4520 "static" : (isFixed ? "fixed" : "absolute")), display: "none",
4521 left: offset.left + "px", top: offset.top + "px"});
4524 showAnim = $.datepicker._get(inst, "showAnim");
4525 duration = $.datepicker._get(inst, "duration");
4526 inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 );
4527 $.datepicker._datepickerShowing = true;
4529 if ( $.effects && $.effects.effect[ showAnim ] ) {
4530 inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration);
4532 inst.dpDiv[showAnim || "show"](showAnim ? duration : null);
4535 if ( $.datepicker._shouldFocusInput( inst ) ) {
4539 $.datepicker._curInst = inst;
4543 /* Generate the date picker content. */
4544 _updateDatepicker: function(inst) {
4545 this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
4546 datepicker_instActive = inst; // for delegate hover events
4547 inst.dpDiv.empty().append(this._generateHTML(inst));
4548 this._attachHandlers(inst);
4551 numMonths = this._getNumberOfMonths(inst),
4552 cols = numMonths[1],
4554 activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" );
4556 if ( activeCell.length > 0 ) {
4557 datepicker_handleMouseover.apply( activeCell.get( 0 ) );
4560 inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");
4562 inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em");
4564 inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") +
4565 "Class"]("ui-datepicker-multi");
4566 inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") +
4567 "Class"]("ui-datepicker-rtl");
4569 if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
4573 // deffered render of the years select (to avoid flashes on Firefox)
4574 if( inst.yearshtml ){
4575 origyearshtml = inst.yearshtml;
4576 setTimeout(function(){
4577 //assure that inst.yearshtml didn't change.
4578 if( origyearshtml === inst.yearshtml && inst.yearshtml ){
4579 inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml);
4581 origyearshtml = inst.yearshtml = null;
4586 // #6694 - don't focus the input if it's already focused
4587 // this breaks the change event in IE
4588 // Support: IE and jQuery <1.9
4589 _shouldFocusInput: function( inst ) {
4590 return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
4593 /* Check positioning to remain on screen. */
4594 _checkOffset: function(inst, offset, isFixed) {
4595 var dpWidth = inst.dpDiv.outerWidth(),
4596 dpHeight = inst.dpDiv.outerHeight(),
4597 inputWidth = inst.input ? inst.input.outerWidth() : 0,
4598 inputHeight = inst.input ? inst.input.outerHeight() : 0,
4599 viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()),
4600 viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop());
4602 offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0);
4603 offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0;
4604 offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
4606 // now check if datepicker is showing outside window viewport - move to a better place if so.
4607 offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
4608 Math.abs(offset.left + dpWidth - viewWidth) : 0);
4609 offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
4610 Math.abs(dpHeight + inputHeight) : 0);
4615 /* Find an object's position on the screen. */
4616 _findPos: function(obj) {
4618 inst = this._getInst(obj),
4619 isRTL = this._get(inst, "isRTL");
4621 while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) {
4622 obj = obj[isRTL ? "previousSibling" : "nextSibling"];
4625 position = $(obj).offset();
4626 return [position.left, position.top];
4629 /* Hide the date picker from view.
4630 * @param input element - the input field attached to the date picker
4632 _hideDatepicker: function(input) {
4633 var showAnim, duration, postProcess, onClose,
4634 inst = this._curInst;
4636 if (!inst || (input && inst !== $.data(input, "datepicker"))) {
4640 if (this._datepickerShowing) {
4641 showAnim = this._get(inst, "showAnim");
4642 duration = this._get(inst, "duration");
4643 postProcess = function() {
4644 $.datepicker._tidyDialog(inst);
4647 // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
4648 if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
4649 inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess);
4651 inst.dpDiv[(showAnim === "slideDown" ? "slideUp" :
4652 (showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess);
4658 this._datepickerShowing = false;
4660 onClose = this._get(inst, "onClose");
4662 onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]);
4665 this._lastInput = null;
4666 if (this._inDialog) {
4667 this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" });
4670 $("body").append(this.dpDiv);
4673 this._inDialog = false;
4677 /* Tidy up after a dialog display. */
4678 _tidyDialog: function(inst) {
4679 inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar");
4682 /* Close date picker if clicked elsewhere. */
4683 _checkExternalClick: function(event) {
4684 if (!$.datepicker._curInst) {
4688 var $target = $(event.target),
4689 inst = $.datepicker._getInst($target[0]);
4691 if ( ( ( $target[0].id !== $.datepicker._mainDivId &&
4692 $target.parents("#" + $.datepicker._mainDivId).length === 0 &&
4693 !$target.hasClass($.datepicker.markerClassName) &&
4694 !$target.closest("." + $.datepicker._triggerClass).length &&
4695 $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) ||
4696 ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) {
4697 $.datepicker._hideDatepicker();
4701 /* Adjust one of the date sub-fields. */
4702 _adjustDate: function(id, offset, period) {
4704 inst = this._getInst(target[0]);
4706 if (this._isDisabledDatepicker(target[0])) {
4709 this._adjustInstDate(inst, offset +
4710 (period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning
4712 this._updateDatepicker(inst);
4715 /* Action for current link. */
4716 _gotoToday: function(id) {
4719 inst = this._getInst(target[0]);
4721 if (this._get(inst, "gotoCurrent") && inst.currentDay) {
4722 inst.selectedDay = inst.currentDay;
4723 inst.drawMonth = inst.selectedMonth = inst.currentMonth;
4724 inst.drawYear = inst.selectedYear = inst.currentYear;
4727 inst.selectedDay = date.getDate();
4728 inst.drawMonth = inst.selectedMonth = date.getMonth();
4729 inst.drawYear = inst.selectedYear = date.getFullYear();
4731 this._notifyChange(inst);
4732 this._adjustDate(target);
4735 /* Action for selecting a new month/year. */
4736 _selectMonthYear: function(id, select, period) {
4738 inst = this._getInst(target[0]);
4740 inst["selected" + (period === "M" ? "Month" : "Year")] =
4741 inst["draw" + (period === "M" ? "Month" : "Year")] =
4742 parseInt(select.options[select.selectedIndex].value,10);
4744 this._notifyChange(inst);
4745 this._adjustDate(target);
4748 /* Action for selecting a day. */
4749 _selectDay: function(id, month, year, td) {
4753 if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
4757 inst = this._getInst(target[0]);
4758 inst.selectedDay = inst.currentDay = $("a", td).html();
4759 inst.selectedMonth = inst.currentMonth = month;
4760 inst.selectedYear = inst.currentYear = year;
4761 this._selectDate(id, this._formatDate(inst,
4762 inst.currentDay, inst.currentMonth, inst.currentYear));
4765 /* Erase the input field and hide the date picker. */
4766 _clearDate: function(id) {
4768 this._selectDate(target, "");
4771 /* Update the input field with the selected date. */
4772 _selectDate: function(id, dateStr) {
4775 inst = this._getInst(target[0]);
4777 dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
4779 inst.input.val(dateStr);
4781 this._updateAlternate(inst);
4783 onSelect = this._get(inst, "onSelect");
4785 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
4786 } else if (inst.input) {
4787 inst.input.trigger("change"); // fire the change event
4791 this._updateDatepicker(inst);
4793 this._hideDatepicker();
4794 this._lastInput = inst.input[0];
4795 if (typeof(inst.input[0]) !== "object") {
4796 inst.input.focus(); // restore focus
4798 this._lastInput = null;
4802 /* Update any alternate field to synchronise with the main field. */
4803 _updateAlternate: function(inst) {
4804 var altFormat, date, dateStr,
4805 altField = this._get(inst, "altField");
4807 if (altField) { // update alternate field too
4808 altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat");
4809 date = this._getDate(inst);
4810 dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
4811 $(altField).each(function() { $(this).val(dateStr); });
4815 /* Set as beforeShowDay function to prevent selection of weekends.
4816 * @param date Date - the date to customise
4817 * @return [boolean, string] - is this date selectable?, what is its CSS class?
4819 noWeekends: function(date) {
4820 var day = date.getDay();
4821 return [(day > 0 && day < 6), ""];
4824 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
4825 * @param date Date - the date to get the week for
4826 * @return number - the number of the week within the year that contains this date
4828 iso8601Week: function(date) {
4830 checkDate = new Date(date.getTime());
4832 // Find Thursday of this week starting on Monday
4833 checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
4835 time = checkDate.getTime();
4836 checkDate.setMonth(0); // Compare with Jan 1
4837 checkDate.setDate(1);
4838 return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
4841 /* Parse a string value into a date object.
4842 * See formatDate below for the possible formats.
4844 * @param format string - the expected format of the date
4845 * @param value string - the date in the above format
4846 * @param settings Object - attributes include:
4847 * shortYearCutoff number - the cutoff year for determining the century (optional)
4848 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
4849 * dayNames string[7] - names of the days from Sunday (optional)
4850 * monthNamesShort string[12] - abbreviated names of the months (optional)
4851 * monthNames string[12] - names of the months (optional)
4852 * @return Date - the extracted date value or null if value is blank
4854 parseDate: function (format, value, settings) {
4855 if (format == null || value == null) {
4856 throw "Invalid arguments";
4859 value = (typeof value === "object" ? value.toString() : value + "");
4864 var iFormat, dim, extra,
4866 shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff,
4867 shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
4868 new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)),
4869 dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
4870 dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
4871 monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
4872 monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
4879 // Check whether a format character is doubled
4880 lookAhead = function(match) {
4881 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
4887 // Extract a number from the string value
4888 getNumber = function(match) {
4889 var isDoubled = lookAhead(match),
4890 size = (match === "@" ? 14 : (match === "!" ? 20 :
4891 (match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))),
4892 minSize = (match === "y" ? size : 1),
4893 digits = new RegExp("^\\d{" + minSize + "," + size + "}"),
4894 num = value.substring(iValue).match(digits);
4896 throw "Missing number at position " + iValue;
4898 iValue += num[0].length;
4899 return parseInt(num[0], 10);
4901 // Extract a name from the string value and convert to an index
4902 getName = function(match, shortNames, longNames) {
4904 names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {
4906 }).sort(function (a, b) {
4907 return -(a[1].length - b[1].length);
4910 $.each(names, function (i, pair) {
4912 if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) {
4914 iValue += name.length;
4921 throw "Unknown name at position " + iValue;
4924 // Confirm that a literal character matches the string value
4925 checkLiteral = function() {
4926 if (value.charAt(iValue) !== format.charAt(iFormat)) {
4927 throw "Unexpected literal at position " + iValue;
4932 for (iFormat = 0; iFormat < format.length; iFormat++) {
4934 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
4940 switch (format.charAt(iFormat)) {
4942 day = getNumber("d");
4945 getName("D", dayNamesShort, dayNames);
4948 doy = getNumber("o");
4951 month = getNumber("m");
4954 month = getName("M", monthNamesShort, monthNames);
4957 year = getNumber("y");
4960 date = new Date(getNumber("@"));
4961 year = date.getFullYear();
4962 month = date.getMonth() + 1;
4963 day = date.getDate();
4966 date = new Date((getNumber("!") - this._ticksTo1970) / 10000);
4967 year = date.getFullYear();
4968 month = date.getMonth() + 1;
4969 day = date.getDate();
4972 if (lookAhead("'")){
4984 if (iValue < value.length){
4985 extra = value.substr(iValue);
4986 if (!/^\s+/.test(extra)) {
4987 throw "Extra/unparsed characters found in date: " + extra;
4992 year = new Date().getFullYear();
4993 } else if (year < 100) {
4994 year += new Date().getFullYear() - new Date().getFullYear() % 100 +
4995 (year <= shortYearCutoff ? 0 : -100);
5002 dim = this._getDaysInMonth(year, month - 1);
5011 date = this._daylightSavingAdjust(new Date(year, month - 1, day));
5012 if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) {
5013 throw "Invalid date"; // E.g. 31/02/00
5018 /* Standard date formats. */
5019 ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
5020 COOKIE: "D, dd M yy",
5021 ISO_8601: "yy-mm-dd",
5022 RFC_822: "D, d M y",
5023 RFC_850: "DD, dd-M-y",
5024 RFC_1036: "D, d M y",
5025 RFC_1123: "D, d M yy",
5026 RFC_2822: "D, d M yy",
5027 RSS: "D, d M y", // RFC 822
5030 W3C: "yy-mm-dd", // ISO 8601
5032 _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
5033 Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
5035 /* Format a date object into a string value.
5036 * The format can be combinations of the following:
5037 * d - day of month (no leading zero)
5038 * dd - day of month (two digit)
5039 * o - day of year (no leading zeros)
5040 * oo - day of year (three digit)
5041 * D - day name short
5042 * DD - day name long
5043 * m - month of year (no leading zero)
5044 * mm - month of year (two digit)
5045 * M - month name short
5046 * MM - month name long
5047 * y - year (two digit)
5048 * yy - year (four digit)
5049 * @ - Unix timestamp (ms since 01/01/1970)
5050 * ! - Windows ticks (100ns since 01/01/0001)
5051 * "..." - literal text
5054 * @param format string - the desired format of the date
5055 * @param date Date - the date value to format
5056 * @param settings Object - attributes include:
5057 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
5058 * dayNames string[7] - names of the days from Sunday (optional)
5059 * monthNamesShort string[12] - abbreviated names of the months (optional)
5060 * monthNames string[12] - names of the months (optional)
5061 * @return string - the date in the above format
5063 formatDate: function (format, date, settings) {
5069 dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
5070 dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
5071 monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
5072 monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
5073 // Check whether a format character is doubled
5074 lookAhead = function(match) {
5075 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
5081 // Format a number, with leading zero if necessary
5082 formatNumber = function(match, value, len) {
5083 var num = "" + value;
5084 if (lookAhead(match)) {
5085 while (num.length < len) {
5091 // Format a name, short or long as requested
5092 formatName = function(match, value, shortNames, longNames) {
5093 return (lookAhead(match) ? longNames[value] : shortNames[value]);
5099 for (iFormat = 0; iFormat < format.length; iFormat++) {
5101 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
5104 output += format.charAt(iFormat);
5107 switch (format.charAt(iFormat)) {
5109 output += formatNumber("d", date.getDate(), 2);
5112 output += formatName("D", date.getDay(), dayNamesShort, dayNames);
5115 output += formatNumber("o",
5116 Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);
5119 output += formatNumber("m", date.getMonth() + 1, 2);
5122 output += formatName("M", date.getMonth(), monthNamesShort, monthNames);
5125 output += (lookAhead("y") ? date.getFullYear() :
5126 (date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100);
5129 output += date.getTime();
5132 output += date.getTime() * 10000 + this._ticksTo1970;
5135 if (lookAhead("'")) {
5142 output += format.charAt(iFormat);
5150 /* Extract all possible characters from the date format. */
5151 _possibleChars: function (format) {
5155 // Check whether a format character is doubled
5156 lookAhead = function(match) {
5157 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
5164 for (iFormat = 0; iFormat < format.length; iFormat++) {
5166 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
5169 chars += format.charAt(iFormat);
5172 switch (format.charAt(iFormat)) {
5173 case "d": case "m": case "y": case "@":
5174 chars += "0123456789";
5177 return null; // Accept anything
5179 if (lookAhead("'")) {
5186 chars += format.charAt(iFormat);
5193 /* Get a setting value, defaulting if necessary. */
5194 _get: function(inst, name) {
5195 return inst.settings[name] !== undefined ?
5196 inst.settings[name] : this._defaults[name];
5199 /* Parse existing date and initialise date picker. */
5200 _setDateFromField: function(inst, noDefault) {
5201 if (inst.input.val() === inst.lastVal) {
5205 var dateFormat = this._get(inst, "dateFormat"),
5206 dates = inst.lastVal = inst.input ? inst.input.val() : null,
5207 defaultDate = this._getDefaultDate(inst),
5209 settings = this._getFormatConfig(inst);
5212 date = this.parseDate(dateFormat, dates, settings) || defaultDate;
5214 dates = (noDefault ? "" : dates);
5216 inst.selectedDay = date.getDate();
5217 inst.drawMonth = inst.selectedMonth = date.getMonth();
5218 inst.drawYear = inst.selectedYear = date.getFullYear();
5219 inst.currentDay = (dates ? date.getDate() : 0);
5220 inst.currentMonth = (dates ? date.getMonth() : 0);
5221 inst.currentYear = (dates ? date.getFullYear() : 0);
5222 this._adjustInstDate(inst);
5225 /* Retrieve the default date shown on opening. */
5226 _getDefaultDate: function(inst) {
5227 return this._restrictMinMax(inst,
5228 this._determineDate(inst, this._get(inst, "defaultDate"), new Date()));
5231 /* A date may be specified as an exact value or a relative one. */
5232 _determineDate: function(inst, date, defaultDate) {
5233 var offsetNumeric = function(offset) {
5234 var date = new Date();
5235 date.setDate(date.getDate() + offset);
5238 offsetString = function(offset) {
5240 return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
5241 offset, $.datepicker._getFormatConfig(inst));
5247 var date = (offset.toLowerCase().match(/^c/) ?
5248 $.datepicker._getDate(inst) : null) || new Date(),
5249 year = date.getFullYear(),
5250 month = date.getMonth(),
5251 day = date.getDate(),
5252 pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
5253 matches = pattern.exec(offset);
5256 switch (matches[2] || "d") {
5257 case "d" : case "D" :
5258 day += parseInt(matches[1],10); break;
5259 case "w" : case "W" :
5260 day += parseInt(matches[1],10) * 7; break;
5261 case "m" : case "M" :
5262 month += parseInt(matches[1],10);
5263 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
5265 case "y": case "Y" :
5266 year += parseInt(matches[1],10);
5267 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
5270 matches = pattern.exec(offset);
5272 return new Date(year, month, day);
5274 newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) :
5275 (typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));
5277 newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate);
5279 newDate.setHours(0);
5280 newDate.setMinutes(0);
5281 newDate.setSeconds(0);
5282 newDate.setMilliseconds(0);
5284 return this._daylightSavingAdjust(newDate);
5287 /* Handle switch to/from daylight saving.
5288 * Hours may be non-zero on daylight saving cut-over:
5289 * > 12 when midnight changeover, but then cannot generate
5290 * midnight datetime, so jump to 1AM, otherwise reset.
5291 * @param date (Date) the date to check
5292 * @return (Date) the corrected date
5294 _daylightSavingAdjust: function(date) {
5298 date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
5302 /* Set the date(s) directly. */
5303 _setDate: function(inst, date, noChange) {
5305 origMonth = inst.selectedMonth,
5306 origYear = inst.selectedYear,
5307 newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
5309 inst.selectedDay = inst.currentDay = newDate.getDate();
5310 inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
5311 inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
5312 if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) {
5313 this._notifyChange(inst);
5315 this._adjustInstDate(inst);
5317 inst.input.val(clear ? "" : this._formatDate(inst));
5321 /* Retrieve the date(s) directly. */
5322 _getDate: function(inst) {
5323 var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null :
5324 this._daylightSavingAdjust(new Date(
5325 inst.currentYear, inst.currentMonth, inst.currentDay)));
5329 /* Attach the onxxx handlers. These are declared statically so
5330 * they work with static code transformers like Caja.
5332 _attachHandlers: function(inst) {
5333 var stepMonths = this._get(inst, "stepMonths"),
5334 id = "#" + inst.id.replace( /\\\\/g, "\\" );
5335 inst.dpDiv.find("[data-handler]").map(function () {
5338 $.datepicker._adjustDate(id, -stepMonths, "M");
5341 $.datepicker._adjustDate(id, +stepMonths, "M");
5344 $.datepicker._hideDatepicker();
5346 today: function () {
5347 $.datepicker._gotoToday(id);
5349 selectDay: function () {
5350 $.datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this);
5353 selectMonth: function () {
5354 $.datepicker._selectMonthYear(id, this, "M");
5357 selectYear: function () {
5358 $.datepicker._selectMonthYear(id, this, "Y");
5362 $(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]);
5366 /* Generate the HTML for the current state of the date picker. */
5367 _generateHTML: function(inst) {
5368 var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
5369 controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
5370 monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
5371 selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
5372 cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
5373 printDate, dRow, tbody, daySettings, otherMonth, unselectable,
5374 tempDate = new Date(),
5375 today = this._daylightSavingAdjust(
5376 new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time
5377 isRTL = this._get(inst, "isRTL"),
5378 showButtonPanel = this._get(inst, "showButtonPanel"),
5379 hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"),
5380 navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"),
5381 numMonths = this._getNumberOfMonths(inst),
5382 showCurrentAtPos = this._get(inst, "showCurrentAtPos"),
5383 stepMonths = this._get(inst, "stepMonths"),
5384 isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1),
5385 currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
5386 new Date(inst.currentYear, inst.currentMonth, inst.currentDay))),
5387 minDate = this._getMinMaxDate(inst, "min"),
5388 maxDate = this._getMinMaxDate(inst, "max"),
5389 drawMonth = inst.drawMonth - showCurrentAtPos,
5390 drawYear = inst.drawYear;
5392 if (drawMonth < 0) {
5397 maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
5398 maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
5399 maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
5400 while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
5402 if (drawMonth < 0) {
5408 inst.drawMonth = drawMonth;
5409 inst.drawYear = drawYear;
5411 prevText = this._get(inst, "prevText");
5412 prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
5413 this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
5414 this._getFormatConfig(inst)));
5416 prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
5417 "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
5418 " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" :
5419 (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>"));
5421 nextText = this._get(inst, "nextText");
5422 nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
5423 this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
5424 this._getFormatConfig(inst)));
5426 next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
5427 "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
5428 " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" :
5429 (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>"));
5431 currentText = this._get(inst, "currentText");
5432 gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today);
5433 currentText = (!navigationAsDateFormat ? currentText :
5434 this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
5436 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'>" +
5437 this._get(inst, "closeText") + "</button>" : "");
5439 buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") +
5440 (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'" +
5441 ">" + currentText + "</button>" : "") + (isRTL ? "" : controls) + "</div>" : "";
5443 firstDay = parseInt(this._get(inst, "firstDay"),10);
5444 firstDay = (isNaN(firstDay) ? 0 : firstDay);
5446 showWeek = this._get(inst, "showWeek");
5447 dayNames = this._get(inst, "dayNames");
5448 dayNamesMin = this._get(inst, "dayNamesMin");
5449 monthNames = this._get(inst, "monthNames");
5450 monthNamesShort = this._get(inst, "monthNamesShort");
5451 beforeShowDay = this._get(inst, "beforeShowDay");
5452 showOtherMonths = this._get(inst, "showOtherMonths");
5453 selectOtherMonths = this._get(inst, "selectOtherMonths");
5454 defaultDate = this._getDefaultDate(inst);
5457 for (row = 0; row < numMonths[0]; row++) {
5460 for (col = 0; col < numMonths[1]; col++) {
5461 selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
5462 cornerClass = " ui-corner-all";
5465 calender += "<div class='ui-datepicker-group";
5466 if (numMonths[1] > 1) {
5468 case 0: calender += " ui-datepicker-group-first";
5469 cornerClass = " ui-corner-" + (isRTL ? "right" : "left"); break;
5470 case numMonths[1]-1: calender += " ui-datepicker-group-last";
5471 cornerClass = " ui-corner-" + (isRTL ? "left" : "right"); break;
5472 default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
5477 calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
5478 (/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") +
5479 (/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") +
5480 this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
5481 row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
5482 "</div><table class='ui-datepicker-calendar'><thead>" +
5484 thead = (showWeek ? "<th class='ui-datepicker-week-col'>" + this._get(inst, "weekHeader") + "</th>" : "");
5485 for (dow = 0; dow < 7; dow++) { // days of the week
5486 day = (dow + firstDay) % 7;
5487 thead += "<th scope='col'" + ((dow + firstDay + 6) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "") + ">" +
5488 "<span title='" + dayNames[day] + "'>" + dayNamesMin[day] + "</span></th>";
5490 calender += thead + "</tr></thead><tbody>";
5491 daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
5492 if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) {
5493 inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
5495 leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
5496 curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate
5497 numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043)
5498 this.maxRows = numRows;
5499 printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
5500 for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows
5502 tbody = (!showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
5503 this._get(inst, "calculateWeek")(printDate) + "</td>");
5504 for (dow = 0; dow < 7; dow++) { // create date picker days
5505 daySettings = (beforeShowDay ?
5506 beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]);
5507 otherMonth = (printDate.getMonth() !== drawMonth);
5508 unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
5509 (minDate && printDate < minDate) || (maxDate && printDate > maxDate);
5510 tbody += "<td class='" +
5511 ((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends
5512 (otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months
5513 ((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key
5514 (defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ?
5515 // or defaultDate is current printedDate and defaultDate is selectedDate
5516 " " + this._dayOverClass : "") + // highlight selected day
5517 (unselectable ? " " + this._unselectableClass + " ui-state-disabled": "") + // highlight unselectable days
5518 (otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates
5519 (printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day
5520 (printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different)
5521 ((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "'") + "'" : "") + // cell title
5522 (unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions
5523 (otherMonth && !showOtherMonths ? " " : // display for other months
5524 (unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
5525 (printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") +
5526 (printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day
5527 (otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months
5528 "' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date
5529 printDate.setDate(printDate.getDate() + 1);
5530 printDate = this._daylightSavingAdjust(printDate);
5532 calender += tbody + "</tr>";
5535 if (drawMonth > 11) {
5539 calender += "</tbody></table>" + (isMultiMonth ? "</div>" +
5540 ((numMonths[0] > 0 && col === numMonths[1]-1) ? "<div class='ui-datepicker-row-break'></div>" : "") : "");
5545 html += buttonPanel;
5546 inst._keyEvent = false;
5550 /* Generate the month and year header. */
5551 _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
5552 secondary, monthNames, monthNamesShort) {
5554 var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
5555 changeMonth = this._get(inst, "changeMonth"),
5556 changeYear = this._get(inst, "changeYear"),
5557 showMonthAfterYear = this._get(inst, "showMonthAfterYear"),
5558 html = "<div class='ui-datepicker-title'>",
5562 if (secondary || !changeMonth) {
5563 monthHtml += "<span class='ui-datepicker-month'>" + monthNames[drawMonth] + "</span>";
5565 inMinYear = (minDate && minDate.getFullYear() === drawYear);
5566 inMaxYear = (maxDate && maxDate.getFullYear() === drawYear);
5567 monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
5568 for ( month = 0; month < 12; month++) {
5569 if ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) {
5570 monthHtml += "<option value='" + month + "'" +
5571 (month === drawMonth ? " selected='selected'" : "") +
5572 ">" + monthNamesShort[month] + "</option>";
5575 monthHtml += "</select>";
5578 if (!showMonthAfterYear) {
5579 html += monthHtml + (secondary || !(changeMonth && changeYear) ? " " : "");
5583 if ( !inst.yearshtml ) {
5584 inst.yearshtml = "";
5585 if (secondary || !changeYear) {
5586 html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
5588 // determine range of years to display
5589 years = this._get(inst, "yearRange").split(":");
5590 thisYear = new Date().getFullYear();
5591 determineYear = function(value) {
5592 var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) :
5593 (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) :
5594 parseInt(value, 10)));
5595 return (isNaN(year) ? thisYear : year);
5597 year = determineYear(years[0]);
5598 endYear = Math.max(year, determineYear(years[1] || ""));
5599 year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
5600 endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
5601 inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
5602 for (; year <= endYear; year++) {
5603 inst.yearshtml += "<option value='" + year + "'" +
5604 (year === drawYear ? " selected='selected'" : "") +
5605 ">" + year + "</option>";
5607 inst.yearshtml += "</select>";
5609 html += inst.yearshtml;
5610 inst.yearshtml = null;
5614 html += this._get(inst, "yearSuffix");
5615 if (showMonthAfterYear) {
5616 html += (secondary || !(changeMonth && changeYear) ? " " : "") + monthHtml;
5618 html += "</div>"; // Close datepicker_header
5622 /* Adjust one of the date sub-fields. */
5623 _adjustInstDate: function(inst, offset, period) {
5624 var year = inst.drawYear + (period === "Y" ? offset : 0),
5625 month = inst.drawMonth + (period === "M" ? offset : 0),
5626 day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0),
5627 date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day)));
5629 inst.selectedDay = date.getDate();
5630 inst.drawMonth = inst.selectedMonth = date.getMonth();
5631 inst.drawYear = inst.selectedYear = date.getFullYear();
5632 if (period === "M" || period === "Y") {
5633 this._notifyChange(inst);
5637 /* Ensure a date is within any min/max bounds. */
5638 _restrictMinMax: function(inst, date) {
5639 var minDate = this._getMinMaxDate(inst, "min"),
5640 maxDate = this._getMinMaxDate(inst, "max"),
5641 newDate = (minDate && date < minDate ? minDate : date);
5642 return (maxDate && newDate > maxDate ? maxDate : newDate);
5645 /* Notify change of month/year. */
5646 _notifyChange: function(inst) {
5647 var onChange = this._get(inst, "onChangeMonthYear");
5649 onChange.apply((inst.input ? inst.input[0] : null),
5650 [inst.selectedYear, inst.selectedMonth + 1, inst]);
5654 /* Determine the number of months to show. */
5655 _getNumberOfMonths: function(inst) {
5656 var numMonths = this._get(inst, "numberOfMonths");
5657 return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths));
5660 /* Determine the current maximum date - ensure no time components are set. */
5661 _getMinMaxDate: function(inst, minMax) {
5662 return this._determineDate(inst, this._get(inst, minMax + "Date"), null);
5665 /* Find the number of days in a given month. */
5666 _getDaysInMonth: function(year, month) {
5667 return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();
5670 /* Find the day of the week of the first of a month. */
5671 _getFirstDayOfMonth: function(year, month) {
5672 return new Date(year, month, 1).getDay();
5675 /* Determines if we should allow a "next/prev" month display change. */
5676 _canAdjustMonth: function(inst, offset, curYear, curMonth) {
5677 var numMonths = this._getNumberOfMonths(inst),
5678 date = this._daylightSavingAdjust(new Date(curYear,
5679 curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
5682 date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
5684 return this._isInRange(inst, date);
5687 /* Is the given date in the accepted range? */
5688 _isInRange: function(inst, date) {
5689 var yearSplit, currentYear,
5690 minDate = this._getMinMaxDate(inst, "min"),
5691 maxDate = this._getMinMaxDate(inst, "max"),
5694 years = this._get(inst, "yearRange");
5696 yearSplit = years.split(":");
5697 currentYear = new Date().getFullYear();
5698 minYear = parseInt(yearSplit[0], 10);
5699 maxYear = parseInt(yearSplit[1], 10);
5700 if ( yearSplit[0].match(/[+\-].*/) ) {
5701 minYear += currentYear;
5703 if ( yearSplit[1].match(/[+\-].*/) ) {
5704 maxYear += currentYear;
5708 return ((!minDate || date.getTime() >= minDate.getTime()) &&
5709 (!maxDate || date.getTime() <= maxDate.getTime()) &&
5710 (!minYear || date.getFullYear() >= minYear) &&
5711 (!maxYear || date.getFullYear() <= maxYear));
5714 /* Provide the configuration settings for formatting/parsing. */
5715 _getFormatConfig: function(inst) {
5716 var shortYearCutoff = this._get(inst, "shortYearCutoff");
5717 shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff :
5718 new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
5719 return {shortYearCutoff: shortYearCutoff,
5720 dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"),
5721 monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")};
5724 /* Format the given date for display. */
5725 _formatDate: function(inst, day, month, year) {
5727 inst.currentDay = inst.selectedDay;
5728 inst.currentMonth = inst.selectedMonth;
5729 inst.currentYear = inst.selectedYear;
5731 var date = (day ? (typeof day === "object" ? day :
5732 this._daylightSavingAdjust(new Date(year, month, day))) :
5733 this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
5734 return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst));
5739 * Bind hover events for datepicker elements.
5740 * Done via delegate so the binding only occurs once in the lifetime of the parent div.
5741 * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
5743 function datepicker_bindHover(dpDiv) {
5744 var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
5745 return dpDiv.delegate(selector, "mouseout", function() {
5746 $(this).removeClass("ui-state-hover");
5747 if (this.className.indexOf("ui-datepicker-prev") !== -1) {
5748 $(this).removeClass("ui-datepicker-prev-hover");
5750 if (this.className.indexOf("ui-datepicker-next") !== -1) {
5751 $(this).removeClass("ui-datepicker-next-hover");
5754 .delegate( selector, "mouseover", datepicker_handleMouseover );
5757 function datepicker_handleMouseover() {
5758 if (!$.datepicker._isDisabledDatepicker( datepicker_instActive.inline? datepicker_instActive.dpDiv.parent()[0] : datepicker_instActive.input[0])) {
5759 $(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");
5760 $(this).addClass("ui-state-hover");
5761 if (this.className.indexOf("ui-datepicker-prev") !== -1) {
5762 $(this).addClass("ui-datepicker-prev-hover");
5764 if (this.className.indexOf("ui-datepicker-next") !== -1) {
5765 $(this).addClass("ui-datepicker-next-hover");
5770 /* jQuery extend now ignores nulls! */
5771 function datepicker_extendRemove(target, props) {
5772 $.extend(target, props);
5773 for (var name in props) {
5774 if (props[name] == null) {
5775 target[name] = props[name];
5781 /* Invoke the datepicker functionality.
5782 @param options string - a command, optionally followed by additional parameters or
5783 Object - settings for attaching new datepicker functionality
5784 @return jQuery object */
5785 $.fn.datepicker = function(options){
5787 /* Verify an empty collection wasn't passed - Fixes #6976 */
5788 if ( !this.length ) {
5792 /* Initialise the date picker. */
5793 if (!$.datepicker.initialized) {
5794 $(document).mousedown($.datepicker._checkExternalClick);
5795 $.datepicker.initialized = true;
5798 /* Append datepicker main container to body if not exist. */
5799 if ($("#"+$.datepicker._mainDivId).length === 0) {
5800 $("body").append($.datepicker.dpDiv);
5803 var otherArgs = Array.prototype.slice.call(arguments, 1);
5804 if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) {
5805 return $.datepicker["_" + options + "Datepicker"].
5806 apply($.datepicker, [this[0]].concat(otherArgs));
5808 if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") {
5809 return $.datepicker["_" + options + "Datepicker"].
5810 apply($.datepicker, [this[0]].concat(otherArgs));
5812 return this.each(function() {
5813 typeof options === "string" ?
5814 $.datepicker["_" + options + "Datepicker"].
5815 apply($.datepicker, [this].concat(otherArgs)) :
5816 $.datepicker._attachDatepicker(this, options);
5820 $.datepicker = new Datepicker(); // singleton instance
5821 $.datepicker.initialized = false;
5822 $.datepicker.uuid = new Date().getTime();
5823 $.datepicker.version = "1.11.2";
5825 var datepicker = $.datepicker;
5829 * jQuery UI Draggable 1.11.2
5830 * http://jqueryui.com
5832 * Copyright 2014 jQuery Foundation and other contributors
5833 * Released under the MIT license.
5834 * http://jquery.org/license
5836 * http://api.jqueryui.com/draggable/
5840 $.widget("ui.draggable", $.ui.mouse, {
5842 widgetEventPrefix: "drag",
5847 connectToSortable: false,
5856 refreshPositions: false,
5858 revertDuration: 500,
5861 scrollSensitivity: 20,
5874 _create: function() {
5876 if ( this.options.helper === "original" ) {
5877 this._setPositionRelative();
5879 if (this.options.addClasses){
5880 this.element.addClass("ui-draggable");
5882 if (this.options.disabled){
5883 this.element.addClass("ui-draggable-disabled");
5885 this._setHandleClassName();
5890 _setOption: function( key, value ) {
5891 this._super( key, value );
5892 if ( key === "handle" ) {
5893 this._removeHandleClassName();
5894 this._setHandleClassName();
5898 _destroy: function() {
5899 if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) {
5900 this.destroyOnClear = true;
5903 this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" );
5904 this._removeHandleClassName();
5905 this._mouseDestroy();
5908 _mouseCapture: function(event) {
5909 var o = this.options;
5911 this._blurActiveElement( event );
5913 // among others, prevent a drag on a resizable-handle
5914 if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) {
5918 //Quit if we're not on a valid handle
5919 this.handle = this._getHandle(event);
5924 this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix );
5930 _blockFrames: function( selector ) {
5931 this.iframeBlocks = this.document.find( selector ).map(function() {
5932 var iframe = $( this );
5935 .css( "position", "absolute" )
5936 .appendTo( iframe.parent() )
5937 .outerWidth( iframe.outerWidth() )
5938 .outerHeight( iframe.outerHeight() )
5939 .offset( iframe.offset() )[ 0 ];
5943 _unblockFrames: function() {
5944 if ( this.iframeBlocks ) {
5945 this.iframeBlocks.remove();
5946 delete this.iframeBlocks;
5950 _blurActiveElement: function( event ) {
5951 var document = this.document[ 0 ];
5953 // Only need to blur if the event occurred on the draggable itself, see #10527
5954 if ( !this.handleElement.is( event.target ) ) {
5959 // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
5962 // Support: IE9, IE10
5963 // If the <body> is blurred, IE will switch windows, see #9520
5964 if ( document.activeElement && document.activeElement.nodeName.toLowerCase() !== "body" ) {
5966 // Blur any element that currently has focus, see #4261
5967 $( document.activeElement ).blur();
5969 } catch ( error ) {}
5972 _mouseStart: function(event) {
5974 var o = this.options;
5976 //Create and append the visible helper
5977 this.helper = this._createHelper(event);
5979 this.helper.addClass("ui-draggable-dragging");
5981 //Cache the helper size
5982 this._cacheHelperProportions();
5984 //If ddmanager is used for droppables, set the global draggable
5985 if ($.ui.ddmanager) {
5986 $.ui.ddmanager.current = this;
5990 * - Position generation -
5991 * This block generates everything position related - it's the core of draggables.
5994 //Cache the margins of the original element
5995 this._cacheMargins();
5997 //Store the helper's css position
5998 this.cssPosition = this.helper.css( "position" );
5999 this.scrollParent = this.helper.scrollParent( true );
6000 this.offsetParent = this.helper.offsetParent();
6001 this.hasFixedAncestor = this.helper.parents().filter(function() {
6002 return $( this ).css( "position" ) === "fixed";
6005 //The element's absolute position on the page minus margins
6006 this.positionAbs = this.element.offset();
6007 this._refreshOffsets( event );
6009 //Generate the original position
6010 this.originalPosition = this.position = this._generatePosition( event, false );
6011 this.originalPageX = event.pageX;
6012 this.originalPageY = event.pageY;
6014 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
6015 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
6017 //Set a containment if given in the options
6018 this._setContainment();
6020 //Trigger event + callbacks
6021 if (this._trigger("start", event) === false) {
6026 //Recache the helper size
6027 this._cacheHelperProportions();
6029 //Prepare the droppable offsets
6030 if ($.ui.ddmanager && !o.dropBehaviour) {
6031 $.ui.ddmanager.prepareOffsets(this, event);
6034 // Reset helper's right/bottom css if they're set and set explicit width/height instead
6035 // as this prevents resizing of elements with right/bottom set (see #7772)
6036 this._normalizeRightBottom();
6038 this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
6040 //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
6041 if ( $.ui.ddmanager ) {
6042 $.ui.ddmanager.dragStart(this, event);
6048 _refreshOffsets: function( event ) {
6050 top: this.positionAbs.top - this.margins.top,
6051 left: this.positionAbs.left - this.margins.left,
6053 parent: this._getParentOffset(),
6054 relative: this._getRelativeOffset()
6057 this.offset.click = {
6058 left: event.pageX - this.offset.left,
6059 top: event.pageY - this.offset.top
6063 _mouseDrag: function(event, noPropagation) {
6064 // reset any necessary cached properties (see #5009)
6065 if ( this.hasFixedAncestor ) {
6066 this.offset.parent = this._getParentOffset();
6069 //Compute the helpers position
6070 this.position = this._generatePosition( event, true );
6071 this.positionAbs = this._convertPositionTo("absolute");
6073 //Call plugins and callbacks and use the resulting position if something is returned
6074 if (!noPropagation) {
6075 var ui = this._uiHash();
6076 if (this._trigger("drag", event, ui) === false) {
6080 this.position = ui.position;
6083 this.helper[ 0 ].style.left = this.position.left + "px";
6084 this.helper[ 0 ].style.top = this.position.top + "px";
6086 if ($.ui.ddmanager) {
6087 $.ui.ddmanager.drag(this, event);
6093 _mouseStop: function(event) {
6095 //If we are using droppables, inform the manager about the drop
6098 if ($.ui.ddmanager && !this.options.dropBehaviour) {
6099 dropped = $.ui.ddmanager.drop(this, event);
6102 //if a drop comes from outside (a sortable)
6104 dropped = this.dropped;
6105 this.dropped = false;
6108 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))) {
6109 $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
6110 if (that._trigger("stop", event) !== false) {
6115 if (this._trigger("stop", event) !== false) {
6123 _mouseUp: function( event ) {
6124 this._unblockFrames();
6126 //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003)
6127 if ( $.ui.ddmanager ) {
6128 $.ui.ddmanager.dragStop(this, event);
6131 // Only need to focus if the event occurred on the draggable itself, see #10527
6132 if ( this.handleElement.is( event.target ) ) {
6133 // The interaction is over; whether or not the click resulted in a drag, focus the element
6134 this.element.focus();
6137 return $.ui.mouse.prototype._mouseUp.call(this, event);
6140 cancel: function() {
6142 if (this.helper.is(".ui-draggable-dragging")) {
6152 _getHandle: function(event) {
6153 return this.options.handle ?
6154 !!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
6158 _setHandleClassName: function() {
6159 this.handleElement = this.options.handle ?
6160 this.element.find( this.options.handle ) : this.element;
6161 this.handleElement.addClass( "ui-draggable-handle" );
6164 _removeHandleClassName: function() {
6165 this.handleElement.removeClass( "ui-draggable-handle" );
6168 _createHelper: function(event) {
6170 var o = this.options,
6171 helperIsFunction = $.isFunction( o.helper ),
6172 helper = helperIsFunction ?
6173 $( o.helper.apply( this.element[ 0 ], [ event ] ) ) :
6174 ( o.helper === "clone" ?
6175 this.element.clone().removeAttr( "id" ) :
6178 if (!helper.parents("body").length) {
6179 helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo));
6182 // http://bugs.jqueryui.com/ticket/9446
6183 // a helper function can return the original element
6184 // which wouldn't have been set to relative in _create
6185 if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) {
6186 this._setPositionRelative();
6189 if (helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) {
6190 helper.css("position", "absolute");
6197 _setPositionRelative: function() {
6198 if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) {
6199 this.element[ 0 ].style.position = "relative";
6203 _adjustOffsetFromHelper: function(obj) {
6204 if (typeof obj === "string") {
6205 obj = obj.split(" ");
6207 if ($.isArray(obj)) {
6208 obj = { left: +obj[0], top: +obj[1] || 0 };
6210 if ("left" in obj) {
6211 this.offset.click.left = obj.left + this.margins.left;
6213 if ("right" in obj) {
6214 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
6217 this.offset.click.top = obj.top + this.margins.top;
6219 if ("bottom" in obj) {
6220 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
6224 _isRootNode: function( element ) {
6225 return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ];
6228 _getParentOffset: function() {
6230 //Get the offsetParent and cache its position
6231 var po = this.offsetParent.offset(),
6232 document = this.document[ 0 ];
6234 // This is a special case where we need to modify a offset calculated on start, since the following happened:
6235 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
6236 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
6237 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
6238 if (this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
6239 po.left += this.scrollParent.scrollLeft();
6240 po.top += this.scrollParent.scrollTop();
6243 if ( this._isRootNode( this.offsetParent[ 0 ] ) ) {
6244 po = { top: 0, left: 0 };
6248 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"), 10) || 0),
6249 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"), 10) || 0)
6254 _getRelativeOffset: function() {
6255 if ( this.cssPosition !== "relative" ) {
6256 return { top: 0, left: 0 };
6259 var p = this.element.position(),
6260 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
6263 top: p.top - ( parseInt(this.helper.css( "top" ), 10) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ),
6264 left: p.left - ( parseInt(this.helper.css( "left" ), 10) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 )
6269 _cacheMargins: function() {
6271 left: (parseInt(this.element.css("marginLeft"), 10) || 0),
6272 top: (parseInt(this.element.css("marginTop"), 10) || 0),
6273 right: (parseInt(this.element.css("marginRight"), 10) || 0),
6274 bottom: (parseInt(this.element.css("marginBottom"), 10) || 0)
6278 _cacheHelperProportions: function() {
6279 this.helperProportions = {
6280 width: this.helper.outerWidth(),
6281 height: this.helper.outerHeight()
6285 _setContainment: function() {
6287 var isUserScrollable, c, ce,
6289 document = this.document[ 0 ];
6291 this.relativeContainer = null;
6293 if ( !o.containment ) {
6294 this.containment = null;
6298 if ( o.containment === "window" ) {
6299 this.containment = [
6300 $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
6301 $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
6302 $( window ).scrollLeft() + $( window ).width() - this.helperProportions.width - this.margins.left,
6303 $( window ).scrollTop() + ( $( window ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
6308 if ( o.containment === "document") {
6309 this.containment = [
6312 $( document ).width() - this.helperProportions.width - this.margins.left,
6313 ( $( document ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
6318 if ( o.containment.constructor === Array ) {
6319 this.containment = o.containment;
6323 if ( o.containment === "parent" ) {
6324 o.containment = this.helper[ 0 ].parentNode;
6327 c = $( o.containment );
6334 isUserScrollable = /(scroll|auto)/.test( c.css( "overflow" ) );
6336 this.containment = [
6337 ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
6338 ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ),
6339 ( isUserScrollable ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
6340 ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) -
6341 ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) -
6342 this.helperProportions.width -
6345 ( isUserScrollable ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
6346 ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) -
6347 ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) -
6348 this.helperProportions.height -
6352 this.relativeContainer = c;
6355 _convertPositionTo: function(d, pos) {
6358 pos = this.position;
6361 var mod = d === "absolute" ? 1 : -1,
6362 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
6366 pos.top + // The absolute mouse position
6367 this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
6368 this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
6369 ( ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod)
6372 pos.left + // The absolute mouse position
6373 this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
6374 this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
6375 ( ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod)
6381 _generatePosition: function( event, constrainPosition ) {
6383 var containment, co, top, left,
6385 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ),
6386 pageX = event.pageX,
6387 pageY = event.pageY;
6390 if ( !scrollIsRootNode || !this.offset.scroll ) {
6391 this.offset.scroll = {
6392 top: this.scrollParent.scrollTop(),
6393 left: this.scrollParent.scrollLeft()
6398 * - Position constraining -
6399 * Constrain the position to a mix of grid, containment.
6402 // If we are not dragging yet, we won't check for options
6403 if ( constrainPosition ) {
6404 if ( this.containment ) {
6405 if ( this.relativeContainer ){
6406 co = this.relativeContainer.offset();
6408 this.containment[ 0 ] + co.left,
6409 this.containment[ 1 ] + co.top,
6410 this.containment[ 2 ] + co.left,
6411 this.containment[ 3 ] + co.top
6414 containment = this.containment;
6417 if (event.pageX - this.offset.click.left < containment[0]) {
6418 pageX = containment[0] + this.offset.click.left;
6420 if (event.pageY - this.offset.click.top < containment[1]) {
6421 pageY = containment[1] + this.offset.click.top;
6423 if (event.pageX - this.offset.click.left > containment[2]) {
6424 pageX = containment[2] + this.offset.click.left;
6426 if (event.pageY - this.offset.click.top > containment[3]) {
6427 pageY = containment[3] + this.offset.click.top;
6432 //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950)
6433 top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY;
6434 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;
6436 left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX;
6437 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;
6440 if ( o.axis === "y" ) {
6441 pageX = this.originalPageX;
6444 if ( o.axis === "x" ) {
6445 pageY = this.originalPageY;
6451 pageY - // The absolute mouse position
6452 this.offset.click.top - // Click offset (relative to the element)
6453 this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
6454 this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
6455 ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) )
6458 pageX - // The absolute mouse position
6459 this.offset.click.left - // Click offset (relative to the element)
6460 this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
6461 this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
6462 ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) )
6468 _clear: function() {
6469 this.helper.removeClass("ui-draggable-dragging");
6470 if (this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) {
6471 this.helper.remove();
6474 this.cancelHelperRemoval = false;
6475 if ( this.destroyOnClear ) {
6480 _normalizeRightBottom: function() {
6481 if ( this.options.axis !== "y" && this.helper.css( "right" ) !== "auto" ) {
6482 this.helper.width( this.helper.width() );
6483 this.helper.css( "right", "auto" );
6485 if ( this.options.axis !== "x" && this.helper.css( "bottom" ) !== "auto" ) {
6486 this.helper.height( this.helper.height() );
6487 this.helper.css( "bottom", "auto" );
6491 // From now on bulk stuff - mainly helpers
6493 _trigger: function( type, event, ui ) {
6494 ui = ui || this._uiHash();
6495 $.ui.plugin.call( this, type, [ event, ui, this ], true );
6497 // Absolute position and offset (see #6884 ) have to be recalculated after plugins
6498 if ( /^(drag|start|stop)/.test( type ) ) {
6499 this.positionAbs = this._convertPositionTo( "absolute" );
6500 ui.offset = this.positionAbs;
6502 return $.Widget.prototype._trigger.call( this, type, event, ui );
6507 _uiHash: function() {
6509 helper: this.helper,
6510 position: this.position,
6511 originalPosition: this.originalPosition,
6512 offset: this.positionAbs
6518 $.ui.plugin.add( "draggable", "connectToSortable", {
6519 start: function( event, ui, draggable ) {
6520 var uiSortable = $.extend( {}, ui, {
6521 item: draggable.element
6524 draggable.sortables = [];
6525 $( draggable.options.connectToSortable ).each(function() {
6526 var sortable = $( this ).sortable( "instance" );
6528 if ( sortable && !sortable.options.disabled ) {
6529 draggable.sortables.push( sortable );
6531 // refreshPositions is called at drag start to refresh the containerCache
6532 // which is used in drag. This ensures it's initialized and synchronized
6533 // with any changes that might have happened on the page since initialization.
6534 sortable.refreshPositions();
6535 sortable._trigger("activate", event, uiSortable);
6539 stop: function( event, ui, draggable ) {
6540 var uiSortable = $.extend( {}, ui, {
6541 item: draggable.element
6544 draggable.cancelHelperRemoval = false;
6546 $.each( draggable.sortables, function() {
6547 var sortable = this;
6549 if ( sortable.isOver ) {
6550 sortable.isOver = 0;
6552 // Allow this sortable to handle removing the helper
6553 draggable.cancelHelperRemoval = true;
6554 sortable.cancelHelperRemoval = false;
6556 // Use _storedCSS To restore properties in the sortable,
6557 // as this also handles revert (#9675) since the draggable
6558 // may have modified them in unexpected ways (#8809)
6559 sortable._storedCSS = {
6560 position: sortable.placeholder.css( "position" ),
6561 top: sortable.placeholder.css( "top" ),
6562 left: sortable.placeholder.css( "left" )
6565 sortable._mouseStop(event);
6567 // Once drag has ended, the sortable should return to using
6568 // its original helper, not the shared helper from draggable
6569 sortable.options.helper = sortable.options._helper;
6571 // Prevent this Sortable from removing the helper.
6572 // However, don't set the draggable to remove the helper
6573 // either as another connected Sortable may yet handle the removal.
6574 sortable.cancelHelperRemoval = true;
6576 sortable._trigger( "deactivate", event, uiSortable );
6580 drag: function( event, ui, draggable ) {
6581 $.each( draggable.sortables, function() {
6582 var innermostIntersecting = false,
6585 // Copy over variables that sortable's _intersectsWith uses
6586 sortable.positionAbs = draggable.positionAbs;
6587 sortable.helperProportions = draggable.helperProportions;
6588 sortable.offset.click = draggable.offset.click;
6590 if ( sortable._intersectsWith( sortable.containerCache ) ) {
6591 innermostIntersecting = true;
6593 $.each( draggable.sortables, function() {
6594 // Copy over variables that sortable's _intersectsWith uses
6595 this.positionAbs = draggable.positionAbs;
6596 this.helperProportions = draggable.helperProportions;
6597 this.offset.click = draggable.offset.click;
6599 if ( this !== sortable &&
6600 this._intersectsWith( this.containerCache ) &&
6601 $.contains( sortable.element[ 0 ], this.element[ 0 ] ) ) {
6602 innermostIntersecting = false;
6605 return innermostIntersecting;
6609 if ( innermostIntersecting ) {
6610 // If it intersects, we use a little isOver variable and set it once,
6611 // so that the move-in stuff gets fired only once.
6612 if ( !sortable.isOver ) {
6613 sortable.isOver = 1;
6615 sortable.currentItem = ui.helper
6616 .appendTo( sortable.element )
6617 .data( "ui-sortable-item", true );
6619 // Store helper option to later restore it
6620 sortable.options._helper = sortable.options.helper;
6622 sortable.options.helper = function() {
6623 return ui.helper[ 0 ];
6626 // Fire the start events of the sortable with our passed browser event,
6627 // and our own helper (so it doesn't create a new one)
6628 event.target = sortable.currentItem[ 0 ];
6629 sortable._mouseCapture( event, true );
6630 sortable._mouseStart( event, true, true );
6632 // Because the browser event is way off the new appended portlet,
6633 // modify necessary variables to reflect the changes
6634 sortable.offset.click.top = draggable.offset.click.top;
6635 sortable.offset.click.left = draggable.offset.click.left;
6636 sortable.offset.parent.left -= draggable.offset.parent.left -
6637 sortable.offset.parent.left;
6638 sortable.offset.parent.top -= draggable.offset.parent.top -
6639 sortable.offset.parent.top;
6641 draggable._trigger( "toSortable", event );
6643 // Inform draggable that the helper is in a valid drop zone,
6644 // used solely in the revert option to handle "valid/invalid".
6645 draggable.dropped = sortable.element;
6647 // Need to refreshPositions of all sortables in the case that
6648 // adding to one sortable changes the location of the other sortables (#9675)
6649 $.each( draggable.sortables, function() {
6650 this.refreshPositions();
6653 // hack so receive/update callbacks work (mostly)
6654 draggable.currentItem = draggable.element;
6655 sortable.fromOutside = draggable;
6658 if ( sortable.currentItem ) {
6659 sortable._mouseDrag( event );
6660 // Copy the sortable's position because the draggable's can potentially reflect
6661 // a relative position, while sortable is always absolute, which the dragged
6662 // element has now become. (#8809)
6663 ui.position = sortable.position;
6666 // If it doesn't intersect with the sortable, and it intersected before,
6667 // we fake the drag stop of the sortable, but make sure it doesn't remove
6668 // the helper by using cancelHelperRemoval.
6669 if ( sortable.isOver ) {
6671 sortable.isOver = 0;
6672 sortable.cancelHelperRemoval = true;
6674 // Calling sortable's mouseStop would trigger a revert,
6675 // so revert must be temporarily false until after mouseStop is called.
6676 sortable.options._revert = sortable.options.revert;
6677 sortable.options.revert = false;
6679 sortable._trigger( "out", event, sortable._uiHash( sortable ) );
6680 sortable._mouseStop( event, true );
6682 // restore sortable behaviors that were modfied
6683 // when the draggable entered the sortable area (#9481)
6684 sortable.options.revert = sortable.options._revert;
6685 sortable.options.helper = sortable.options._helper;
6687 if ( sortable.placeholder ) {
6688 sortable.placeholder.remove();
6691 // Recalculate the draggable's offset considering the sortable
6692 // may have modified them in unexpected ways (#8809)
6693 draggable._refreshOffsets( event );
6694 ui.position = draggable._generatePosition( event, true );
6696 draggable._trigger( "fromSortable", event );
6698 // Inform draggable that the helper is no longer in a valid drop zone
6699 draggable.dropped = false;
6701 // Need to refreshPositions of all sortables just in case removing
6702 // from one sortable changes the location of other sortables (#9675)
6703 $.each( draggable.sortables, function() {
6704 this.refreshPositions();
6712 $.ui.plugin.add("draggable", "cursor", {
6713 start: function( event, ui, instance ) {
6714 var t = $( "body" ),
6715 o = instance.options;
6717 if (t.css("cursor")) {
6718 o._cursor = t.css("cursor");
6720 t.css("cursor", o.cursor);
6722 stop: function( event, ui, instance ) {
6723 var o = instance.options;
6725 $("body").css("cursor", o._cursor);
6730 $.ui.plugin.add("draggable", "opacity", {
6731 start: function( event, ui, instance ) {
6732 var t = $( ui.helper ),
6733 o = instance.options;
6734 if (t.css("opacity")) {
6735 o._opacity = t.css("opacity");
6737 t.css("opacity", o.opacity);
6739 stop: function( event, ui, instance ) {
6740 var o = instance.options;
6742 $(ui.helper).css("opacity", o._opacity);
6747 $.ui.plugin.add("draggable", "scroll", {
6748 start: function( event, ui, i ) {
6749 if ( !i.scrollParentNotHidden ) {
6750 i.scrollParentNotHidden = i.helper.scrollParent( false );
6753 if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] && i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) {
6754 i.overflowOffset = i.scrollParentNotHidden.offset();
6757 drag: function( event, ui, i ) {
6761 scrollParent = i.scrollParentNotHidden[ 0 ],
6762 document = i.document[ 0 ];
6764 if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) {
6765 if ( !o.axis || o.axis !== "x" ) {
6766 if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY < o.scrollSensitivity ) {
6767 scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed;
6768 } else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) {
6769 scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed;
6773 if ( !o.axis || o.axis !== "y" ) {
6774 if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX < o.scrollSensitivity ) {
6775 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed;
6776 } else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) {
6777 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed;
6783 if (!o.axis || o.axis !== "x") {
6784 if (event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
6785 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
6786 } else if ($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
6787 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
6791 if (!o.axis || o.axis !== "y") {
6792 if (event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
6793 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
6794 } else if ($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
6795 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
6801 if (scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
6802 $.ui.ddmanager.prepareOffsets(i, event);
6808 $.ui.plugin.add("draggable", "snap", {
6809 start: function( event, ui, i ) {
6813 i.snapElements = [];
6815 $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() {
6818 if (this !== i.element[0]) {
6819 i.snapElements.push({
6821 width: $t.outerWidth(), height: $t.outerHeight(),
6822 top: $o.top, left: $o.left
6828 drag: function( event, ui, inst ) {
6830 var ts, bs, ls, rs, l, r, t, b, i, first,
6832 d = o.snapTolerance,
6833 x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
6834 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
6836 for (i = inst.snapElements.length - 1; i >= 0; i--){
6838 l = inst.snapElements[i].left - inst.margins.left;
6839 r = l + inst.snapElements[i].width;
6840 t = inst.snapElements[i].top - inst.margins.top;
6841 b = t + inst.snapElements[i].height;
6843 if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || !$.contains( inst.snapElements[ i ].item.ownerDocument, inst.snapElements[ i ].item ) ) {
6844 if (inst.snapElements[i].snapping) {
6845 (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
6847 inst.snapElements[i].snapping = false;
6851 if (o.snapMode !== "inner") {
6852 ts = Math.abs(t - y2) <= d;
6853 bs = Math.abs(b - y1) <= d;
6854 ls = Math.abs(l - x2) <= d;
6855 rs = Math.abs(r - x1) <= d;
6857 ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top;
6860 ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top;
6863 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left;
6866 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left;
6870 first = (ts || bs || ls || rs);
6872 if (o.snapMode !== "outer") {
6873 ts = Math.abs(t - y1) <= d;
6874 bs = Math.abs(b - y2) <= d;
6875 ls = Math.abs(l - x1) <= d;
6876 rs = Math.abs(r - x2) <= d;
6878 ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top;
6881 ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top;
6884 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left;
6887 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left;
6891 if (!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) {
6892 (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
6894 inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
6901 $.ui.plugin.add("draggable", "stack", {
6902 start: function( event, ui, instance ) {
6904 o = instance.options,
6905 group = $.makeArray($(o.stack)).sort(function(a, b) {
6906 return (parseInt($(a).css("zIndex"), 10) || 0) - (parseInt($(b).css("zIndex"), 10) || 0);
6909 if (!group.length) { return; }
6911 min = parseInt($(group[0]).css("zIndex"), 10) || 0;
6912 $(group).each(function(i) {
6913 $(this).css("zIndex", min + i);
6915 this.css("zIndex", (min + group.length));
6919 $.ui.plugin.add("draggable", "zIndex", {
6920 start: function( event, ui, instance ) {
6921 var t = $( ui.helper ),
6922 o = instance.options;
6924 if (t.css("zIndex")) {
6925 o._zIndex = t.css("zIndex");
6927 t.css("zIndex", o.zIndex);
6929 stop: function( event, ui, instance ) {
6930 var o = instance.options;
6933 $(ui.helper).css("zIndex", o._zIndex);
6938 var draggable = $.ui.draggable;
6942 * jQuery UI Resizable 1.11.2
6943 * http://jqueryui.com
6945 * Copyright 2014 jQuery Foundation and other contributors
6946 * Released under the MIT license.
6947 * http://jquery.org/license
6949 * http://api.jqueryui.com/resizable/
6953 $.widget("ui.resizable", $.ui.mouse, {
6955 widgetEventPrefix: "resize",
6959 animateDuration: "slow",
6960 animateEasing: "swing",
6981 _num: function( value ) {
6982 return parseInt( value, 10 ) || 0;
6985 _isNumber: function( value ) {
6986 return !isNaN( parseInt( value, 10 ) );
6989 _hasScroll: function( el, a ) {
6991 if ( $( el ).css( "overflow" ) === "hidden") {
6995 var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
6998 if ( el[ scroll ] > 0 ) {
7002 // TODO: determine which cases actually cause this to happen
7003 // if the element doesn't have the scroll set, see if it's possible to
7006 has = ( el[ scroll ] > 0 );
7011 _create: function() {
7013 var n, i, handle, axis, hname,
7016 this.element.addClass("ui-resizable");
7019 _aspectRatio: !!(o.aspectRatio),
7020 aspectRatio: o.aspectRatio,
7021 originalElement: this.element,
7022 _proportionallyResizeElements: [],
7023 _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
7026 // Wrap the element if it cannot hold child nodes
7027 if (this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) {
7030 $("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({
7031 position: this.element.css("position"),
7032 width: this.element.outerWidth(),
7033 height: this.element.outerHeight(),
7034 top: this.element.css("top"),
7035 left: this.element.css("left")
7039 this.element = this.element.parent().data(
7040 "ui-resizable", this.element.resizable( "instance" )
7043 this.elementIsWrapper = true;
7046 marginLeft: this.originalElement.css("marginLeft"),
7047 marginTop: this.originalElement.css("marginTop"),
7048 marginRight: this.originalElement.css("marginRight"),
7049 marginBottom: this.originalElement.css("marginBottom")
7051 this.originalElement.css({
7058 // Prevent Safari textarea resize
7059 this.originalResizeStyle = this.originalElement.css("resize");
7060 this.originalElement.css("resize", "none");
7062 this._proportionallyResizeElements.push( this.originalElement.css({
7069 // avoid IE jump (hard set the margin)
7070 this.originalElement.css({ margin: this.originalElement.css("margin") });
7072 this._proportionallyResize();
7075 this.handles = o.handles ||
7076 ( !$(".ui-resizable-handle", this.element).length ?
7078 n: ".ui-resizable-n",
7079 e: ".ui-resizable-e",
7080 s: ".ui-resizable-s",
7081 w: ".ui-resizable-w",
7082 se: ".ui-resizable-se",
7083 sw: ".ui-resizable-sw",
7084 ne: ".ui-resizable-ne",
7085 nw: ".ui-resizable-nw"
7088 if (this.handles.constructor === String) {
7090 if ( this.handles === "all") {
7091 this.handles = "n,e,s,w,se,sw,ne,nw";
7094 n = this.handles.split(",");
7097 for (i = 0; i < n.length; i++) {
7099 handle = $.trim(n[i]);
7100 hname = "ui-resizable-" + handle;
7101 axis = $("<div class='ui-resizable-handle " + hname + "'></div>");
7103 axis.css({ zIndex: o.zIndex });
7105 // TODO : What's going on here?
7106 if ("se" === handle) {
7107 axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se");
7110 this.handles[handle] = ".ui-resizable-" + handle;
7111 this.element.append(axis);
7116 this._renderAxis = function(target) {
7118 var i, axis, padPos, padWrapper;
7120 target = target || this.element;
7122 for (i in this.handles) {
7124 if (this.handles[i].constructor === String) {
7125 this.handles[i] = this.element.children( this.handles[ i ] ).first().show();
7128 if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) {
7130 axis = $(this.handles[i], this.element);
7132 padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
7134 padPos = [ "padding",
7135 /ne|nw|n/.test(i) ? "Top" :
7136 /se|sw|s/.test(i) ? "Bottom" :
7137 /^e$/.test(i) ? "Right" : "Left" ].join("");
7139 target.css(padPos, padWrapper);
7141 this._proportionallyResize();
7145 // TODO: What's that good for? There's not anything to be executed left
7146 if (!$(this.handles[i]).length) {
7152 // TODO: make renderAxis a prototype function
7153 this._renderAxis(this.element);
7155 this._handles = $(".ui-resizable-handle", this.element)
7156 .disableSelection();
7158 this._handles.mouseover(function() {
7159 if (!that.resizing) {
7160 if (this.className) {
7161 axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
7163 that.axis = axis && axis[1] ? axis[1] : "se";
7168 this._handles.hide();
7170 .addClass("ui-resizable-autohide")
7171 .mouseenter(function() {
7175 $(this).removeClass("ui-resizable-autohide");
7176 that._handles.show();
7178 .mouseleave(function() {
7182 if (!that.resizing) {
7183 $(this).addClass("ui-resizable-autohide");
7184 that._handles.hide();
7193 _destroy: function() {
7195 this._mouseDestroy();
7198 _destroy = function(exp) {
7200 .removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing")
7201 .removeData("resizable")
7202 .removeData("ui-resizable")
7203 .unbind(".resizable")
7204 .find(".ui-resizable-handle")
7208 // TODO: Unwrap at same DOM position
7209 if (this.elementIsWrapper) {
7210 _destroy(this.element);
7211 wrapper = this.element;
7212 this.originalElement.css({
7213 position: wrapper.css("position"),
7214 width: wrapper.outerWidth(),
7215 height: wrapper.outerHeight(),
7216 top: wrapper.css("top"),
7217 left: wrapper.css("left")
7218 }).insertAfter( wrapper );
7222 this.originalElement.css("resize", this.originalResizeStyle);
7223 _destroy(this.originalElement);
7228 _mouseCapture: function(event) {
7232 for (i in this.handles) {
7233 handle = $(this.handles[i])[0];
7234 if (handle === event.target || $.contains(handle, event.target)) {
7239 return !this.options.disabled && capture;
7242 _mouseStart: function(event) {
7244 var curleft, curtop, cursor,
7248 this.resizing = true;
7250 this._renderProxy();
7252 curleft = this._num(this.helper.css("left"));
7253 curtop = this._num(this.helper.css("top"));
7255 if (o.containment) {
7256 curleft += $(o.containment).scrollLeft() || 0;
7257 curtop += $(o.containment).scrollTop() || 0;
7260 this.offset = this.helper.offset();
7261 this.position = { left: curleft, top: curtop };
7263 this.size = this._helper ? {
7264 width: this.helper.width(),
7265 height: this.helper.height()
7271 this.originalSize = this._helper ? {
7272 width: el.outerWidth(),
7273 height: el.outerHeight()
7280 width: el.outerWidth() - el.width(),
7281 height: el.outerHeight() - el.height()
7284 this.originalPosition = { left: curleft, top: curtop };
7285 this.originalMousePosition = { left: event.pageX, top: event.pageY };
7287 this.aspectRatio = (typeof o.aspectRatio === "number") ?
7289 ((this.originalSize.width / this.originalSize.height) || 1);
7291 cursor = $(".ui-resizable-" + this.axis).css("cursor");
7292 $("body").css("cursor", cursor === "auto" ? this.axis + "-resize" : cursor);
7294 el.addClass("ui-resizable-resizing");
7295 this._propagate("start", event);
7299 _mouseDrag: function(event) {
7302 smp = this.originalMousePosition,
7304 dx = (event.pageX - smp.left) || 0,
7305 dy = (event.pageY - smp.top) || 0,
7306 trigger = this._change[a];
7308 this._updatePrevProperties();
7314 data = trigger.apply(this, [ event, dx, dy ]);
7316 this._updateVirtualBoundaries(event.shiftKey);
7317 if (this._aspectRatio || event.shiftKey) {
7318 data = this._updateRatio(data, event);
7321 data = this._respectSize(data, event);
7323 this._updateCache(data);
7325 this._propagate("resize", event);
7327 props = this._applyChanges();
7329 if ( !this._helper && this._proportionallyResizeElements.length ) {
7330 this._proportionallyResize();
7333 if ( !$.isEmptyObject( props ) ) {
7334 this._updatePrevProperties();
7335 this._trigger( "resize", event, this.ui() );
7336 this._applyChanges();
7342 _mouseStop: function(event) {
7344 this.resizing = false;
7345 var pr, ista, soffseth, soffsetw, s, left, top,
7346 o = this.options, that = this;
7350 pr = this._proportionallyResizeElements;
7351 ista = pr.length && (/textarea/i).test(pr[0].nodeName);
7352 soffseth = ista && this._hasScroll(pr[0], "left") ? 0 : that.sizeDiff.height;
7353 soffsetw = ista ? 0 : that.sizeDiff.width;
7356 width: (that.helper.width() - soffsetw),
7357 height: (that.helper.height() - soffseth)
7359 left = (parseInt(that.element.css("left"), 10) +
7360 (that.position.left - that.originalPosition.left)) || null;
7361 top = (parseInt(that.element.css("top"), 10) +
7362 (that.position.top - that.originalPosition.top)) || null;
7365 this.element.css($.extend(s, { top: top, left: left }));
7368 that.helper.height(that.size.height);
7369 that.helper.width(that.size.width);
7371 if (this._helper && !o.animate) {
7372 this._proportionallyResize();
7376 $("body").css("cursor", "auto");
7378 this.element.removeClass("ui-resizable-resizing");
7380 this._propagate("stop", event);
7383 this.helper.remove();
7390 _updatePrevProperties: function() {
7391 this.prevPosition = {
7392 top: this.position.top,
7393 left: this.position.left
7396 width: this.size.width,
7397 height: this.size.height
7401 _applyChanges: function() {
7404 if ( this.position.top !== this.prevPosition.top ) {
7405 props.top = this.position.top + "px";
7407 if ( this.position.left !== this.prevPosition.left ) {
7408 props.left = this.position.left + "px";
7410 if ( this.size.width !== this.prevSize.width ) {
7411 props.width = this.size.width + "px";
7413 if ( this.size.height !== this.prevSize.height ) {
7414 props.height = this.size.height + "px";
7417 this.helper.css( props );
7422 _updateVirtualBoundaries: function(forceAspectRatio) {
7423 var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
7427 minWidth: this._isNumber(o.minWidth) ? o.minWidth : 0,
7428 maxWidth: this._isNumber(o.maxWidth) ? o.maxWidth : Infinity,
7429 minHeight: this._isNumber(o.minHeight) ? o.minHeight : 0,
7430 maxHeight: this._isNumber(o.maxHeight) ? o.maxHeight : Infinity
7433 if (this._aspectRatio || forceAspectRatio) {
7434 pMinWidth = b.minHeight * this.aspectRatio;
7435 pMinHeight = b.minWidth / this.aspectRatio;
7436 pMaxWidth = b.maxHeight * this.aspectRatio;
7437 pMaxHeight = b.maxWidth / this.aspectRatio;
7439 if (pMinWidth > b.minWidth) {
7440 b.minWidth = pMinWidth;
7442 if (pMinHeight > b.minHeight) {
7443 b.minHeight = pMinHeight;
7445 if (pMaxWidth < b.maxWidth) {
7446 b.maxWidth = pMaxWidth;
7448 if (pMaxHeight < b.maxHeight) {
7449 b.maxHeight = pMaxHeight;
7452 this._vBoundaries = b;
7455 _updateCache: function(data) {
7456 this.offset = this.helper.offset();
7457 if (this._isNumber(data.left)) {
7458 this.position.left = data.left;
7460 if (this._isNumber(data.top)) {
7461 this.position.top = data.top;
7463 if (this._isNumber(data.height)) {
7464 this.size.height = data.height;
7466 if (this._isNumber(data.width)) {
7467 this.size.width = data.width;
7471 _updateRatio: function( data ) {
7473 var cpos = this.position,
7477 if (this._isNumber(data.height)) {
7478 data.width = (data.height * this.aspectRatio);
7479 } else if (this._isNumber(data.width)) {
7480 data.height = (data.width / this.aspectRatio);
7484 data.left = cpos.left + (csize.width - data.width);
7488 data.top = cpos.top + (csize.height - data.height);
7489 data.left = cpos.left + (csize.width - data.width);
7495 _respectSize: function( data ) {
7497 var o = this._vBoundaries,
7499 ismaxw = this._isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width),
7500 ismaxh = this._isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height),
7501 isminw = this._isNumber(data.width) && o.minWidth && (o.minWidth > data.width),
7502 isminh = this._isNumber(data.height) && o.minHeight && (o.minHeight > data.height),
7503 dw = this.originalPosition.left + this.originalSize.width,
7504 dh = this.position.top + this.size.height,
7505 cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
7507 data.width = o.minWidth;
7510 data.height = o.minHeight;
7513 data.width = o.maxWidth;
7516 data.height = o.maxHeight;
7520 data.left = dw - o.minWidth;
7523 data.left = dw - o.maxWidth;
7526 data.top = dh - o.minHeight;
7529 data.top = dh - o.maxHeight;
7532 // Fixing jump error on top/left - bug #2330
7533 if (!data.width && !data.height && !data.left && data.top) {
7535 } else if (!data.width && !data.height && !data.top && data.left) {
7542 _getPaddingPlusBorderDimensions: function( element ) {
7546 element.css( "borderTopWidth" ),
7547 element.css( "borderRightWidth" ),
7548 element.css( "borderBottomWidth" ),
7549 element.css( "borderLeftWidth" )
7552 element.css( "paddingTop" ),
7553 element.css( "paddingRight" ),
7554 element.css( "paddingBottom" ),
7555 element.css( "paddingLeft" )
7558 for ( ; i < 4; i++ ) {
7559 widths[ i ] = ( parseInt( borders[ i ], 10 ) || 0 );
7560 widths[ i ] += ( parseInt( paddings[ i ], 10 ) || 0 );
7564 height: widths[ 0 ] + widths[ 2 ],
7565 width: widths[ 1 ] + widths[ 3 ]
7569 _proportionallyResize: function() {
7571 if (!this._proportionallyResizeElements.length) {
7577 element = this.helper || this.element;
7579 for ( ; i < this._proportionallyResizeElements.length; i++) {
7581 prel = this._proportionallyResizeElements[i];
7583 // TODO: Seems like a bug to cache this.outerDimensions
7584 // considering that we are in a loop.
7585 if (!this.outerDimensions) {
7586 this.outerDimensions = this._getPaddingPlusBorderDimensions( prel );
7590 height: (element.height() - this.outerDimensions.height) || 0,
7591 width: (element.width() - this.outerDimensions.width) || 0
7598 _renderProxy: function() {
7600 var el = this.element, o = this.options;
7601 this.elementOffset = el.offset();
7605 this.helper = this.helper || $("<div style='overflow:hidden;'></div>");
7607 this.helper.addClass(this._helper).css({
7608 width: this.element.outerWidth() - 1,
7609 height: this.element.outerHeight() - 1,
7610 position: "absolute",
7611 left: this.elementOffset.left + "px",
7612 top: this.elementOffset.top + "px",
7613 zIndex: ++o.zIndex //TODO: Don't modify option
7618 .disableSelection();
7621 this.helper = this.element;
7627 e: function(event, dx) {
7628 return { width: this.originalSize.width + dx };
7630 w: function(event, dx) {
7631 var cs = this.originalSize, sp = this.originalPosition;
7632 return { left: sp.left + dx, width: cs.width - dx };
7634 n: function(event, dx, dy) {
7635 var cs = this.originalSize, sp = this.originalPosition;
7636 return { top: sp.top + dy, height: cs.height - dy };
7638 s: function(event, dx, dy) {
7639 return { height: this.originalSize.height + dy };
7641 se: function(event, dx, dy) {
7642 return $.extend(this._change.s.apply(this, arguments),
7643 this._change.e.apply(this, [ event, dx, dy ]));
7645 sw: function(event, dx, dy) {
7646 return $.extend(this._change.s.apply(this, arguments),
7647 this._change.w.apply(this, [ event, dx, dy ]));
7649 ne: function(event, dx, dy) {
7650 return $.extend(this._change.n.apply(this, arguments),
7651 this._change.e.apply(this, [ event, dx, dy ]));
7653 nw: function(event, dx, dy) {
7654 return $.extend(this._change.n.apply(this, arguments),
7655 this._change.w.apply(this, [ event, dx, dy ]));
7659 _propagate: function(n, event) {
7660 $.ui.plugin.call(this, n, [ event, this.ui() ]);
7661 (n !== "resize" && this._trigger(n, event, this.ui()));
7668 originalElement: this.originalElement,
7669 element: this.element,
7670 helper: this.helper,
7671 position: this.position,
7673 originalSize: this.originalSize,
7674 originalPosition: this.originalPosition
7681 * Resizable Extensions
7684 $.ui.plugin.add("resizable", "animate", {
7686 stop: function( event ) {
7687 var that = $(this).resizable( "instance" ),
7689 pr = that._proportionallyResizeElements,
7690 ista = pr.length && (/textarea/i).test(pr[0].nodeName),
7691 soffseth = ista && that._hasScroll(pr[0], "left") ? 0 : that.sizeDiff.height,
7692 soffsetw = ista ? 0 : that.sizeDiff.width,
7693 style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) },
7694 left = (parseInt(that.element.css("left"), 10) +
7695 (that.position.left - that.originalPosition.left)) || null,
7696 top = (parseInt(that.element.css("top"), 10) +
7697 (that.position.top - that.originalPosition.top)) || null;
7699 that.element.animate(
7700 $.extend(style, top && left ? { top: top, left: left } : {}), {
7701 duration: o.animateDuration,
7702 easing: o.animateEasing,
7706 width: parseInt(that.element.css("width"), 10),
7707 height: parseInt(that.element.css("height"), 10),
7708 top: parseInt(that.element.css("top"), 10),
7709 left: parseInt(that.element.css("left"), 10)
7712 if (pr && pr.length) {
7713 $(pr[0]).css({ width: data.width, height: data.height });
7716 // propagating resize, and updating values for each animation step
7717 that._updateCache(data);
7718 that._propagate("resize", event);
7727 $.ui.plugin.add( "resizable", "containment", {
7730 var element, p, co, ch, cw, width, height,
7731 that = $( this ).resizable( "instance" ),
7735 ce = ( oc instanceof $ ) ? oc.get( 0 ) : ( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc;
7741 that.containerElement = $( ce );
7743 if ( /document/.test( oc ) || oc === document ) {
7744 that.containerOffset = {
7748 that.containerPosition = {
7754 element: $( document ),
7757 width: $( document ).width(),
7758 height: $( document ).height() || document.body.parentNode.scrollHeight
7763 $([ "Top", "Right", "Left", "Bottom" ]).each(function( i, name ) {
7764 p[ i ] = that._num( element.css( "padding" + name ) );
7767 that.containerOffset = element.offset();
7768 that.containerPosition = element.position();
7769 that.containerSize = {
7770 height: ( element.innerHeight() - p[ 3 ] ),
7771 width: ( element.innerWidth() - p[ 1 ] )
7774 co = that.containerOffset;
7775 ch = that.containerSize.height;
7776 cw = that.containerSize.width;
7777 width = ( that._hasScroll ( ce, "left" ) ? ce.scrollWidth : cw );
7778 height = ( that._hasScroll ( ce ) ? ce.scrollHeight : ch ) ;
7790 resize: function( event ) {
7791 var woset, hoset, isParent, isOffsetRelative,
7792 that = $( this ).resizable( "instance" ),
7794 co = that.containerOffset,
7796 pRatio = that._aspectRatio || event.shiftKey,
7801 ce = that.containerElement,
7802 continueResize = true;
7804 if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) {
7808 if ( cp.left < ( that._helper ? co.left : 0 ) ) {
7809 that.size.width = that.size.width +
7811 ( that.position.left - co.left ) :
7812 ( that.position.left - cop.left ) );
7815 that.size.height = that.size.width / that.aspectRatio;
7816 continueResize = false;
7818 that.position.left = o.helper ? co.left : 0;
7821 if ( cp.top < ( that._helper ? co.top : 0 ) ) {
7822 that.size.height = that.size.height +
7824 ( that.position.top - co.top ) :
7825 that.position.top );
7828 that.size.width = that.size.height * that.aspectRatio;
7829 continueResize = false;
7831 that.position.top = that._helper ? co.top : 0;
7834 isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 );
7835 isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) );
7837 if ( isParent && isOffsetRelative ) {
7838 that.offset.left = that.parentData.left + that.position.left;
7839 that.offset.top = that.parentData.top + that.position.top;
7841 that.offset.left = that.element.offset().left;
7842 that.offset.top = that.element.offset().top;
7845 woset = Math.abs( that.sizeDiff.width +
7847 that.offset.left - cop.left :
7848 (that.offset.left - co.left)) );
7850 hoset = Math.abs( that.sizeDiff.height +
7852 that.offset.top - cop.top :
7853 (that.offset.top - co.top)) );
7855 if ( woset + that.size.width >= that.parentData.width ) {
7856 that.size.width = that.parentData.width - woset;
7858 that.size.height = that.size.width / that.aspectRatio;
7859 continueResize = false;
7863 if ( hoset + that.size.height >= that.parentData.height ) {
7864 that.size.height = that.parentData.height - hoset;
7866 that.size.width = that.size.height * that.aspectRatio;
7867 continueResize = false;
7871 if ( !continueResize ){
7872 that.position.left = that.prevPosition.left;
7873 that.position.top = that.prevPosition.top;
7874 that.size.width = that.prevSize.width;
7875 that.size.height = that.prevSize.height;
7880 var that = $( this ).resizable( "instance" ),
7882 co = that.containerOffset,
7883 cop = that.containerPosition,
7884 ce = that.containerElement,
7885 helper = $( that.helper ),
7886 ho = helper.offset(),
7887 w = helper.outerWidth() - that.sizeDiff.width,
7888 h = helper.outerHeight() - that.sizeDiff.height;
7890 if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) {
7892 left: ho.left - cop.left - co.left,
7898 if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) {
7900 left: ho.left - cop.left - co.left,
7908 $.ui.plugin.add("resizable", "alsoResize", {
7911 var that = $(this).resizable( "instance" ),
7913 _store = function(exp) {
7914 $(exp).each(function() {
7916 el.data("ui-resizable-alsoresize", {
7917 width: parseInt(el.width(), 10), height: parseInt(el.height(), 10),
7918 left: parseInt(el.css("left"), 10), top: parseInt(el.css("top"), 10)
7923 if (typeof(o.alsoResize) === "object" && !o.alsoResize.parentNode) {
7924 if (o.alsoResize.length) {
7925 o.alsoResize = o.alsoResize[0];
7926 _store(o.alsoResize);
7928 $.each(o.alsoResize, function(exp) {
7933 _store(o.alsoResize);
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 _alsoResize = function(exp, c) {
7950 $(exp).each(function() {
7951 var el = $(this), start = $(this).data("ui-resizable-alsoresize"), style = {},
7952 css = c && c.length ?
7954 el.parents(ui.originalElement[0]).length ?
7955 [ "width", "height" ] :
7956 [ "width", "height", "top", "left" ];
7958 $.each(css, function(i, prop) {
7959 var sum = (start[prop] || 0) + (delta[prop] || 0);
7960 if (sum && sum >= 0) {
7961 style[prop] = sum || null;
7969 if (typeof(o.alsoResize) === "object" && !o.alsoResize.nodeType) {
7970 $.each(o.alsoResize, function(exp, c) {
7971 _alsoResize(exp, c);
7974 _alsoResize(o.alsoResize);
7979 $(this).removeData("resizable-alsoresize");
7983 $.ui.plugin.add("resizable", "ghost", {
7987 var that = $(this).resizable( "instance" ), o = that.options, cs = that.size;
7989 that.ghost = that.originalElement.clone();
7994 position: "relative",
8001 .addClass("ui-resizable-ghost")
8002 .addClass(typeof o.ghost === "string" ? o.ghost : "");
8004 that.ghost.appendTo(that.helper);
8008 resize: function() {
8009 var that = $(this).resizable( "instance" );
8012 position: "relative",
8013 height: that.size.height,
8014 width: that.size.width
8020 var that = $(this).resizable( "instance" );
8021 if (that.ghost && that.helper) {
8022 that.helper.get(0).removeChild(that.ghost.get(0));
8028 $.ui.plugin.add("resizable", "grid", {
8030 resize: function() {
8031 var outerDimensions,
8032 that = $(this).resizable( "instance" ),
8035 os = that.originalSize,
8036 op = that.originalPosition,
8038 grid = typeof o.grid === "number" ? [ o.grid, o.grid ] : o.grid,
8039 gridX = (grid[0] || 1),
8040 gridY = (grid[1] || 1),
8041 ox = Math.round((cs.width - os.width) / gridX) * gridX,
8042 oy = Math.round((cs.height - os.height) / gridY) * gridY,
8043 newWidth = os.width + ox,
8044 newHeight = os.height + oy,
8045 isMaxWidth = o.maxWidth && (o.maxWidth < newWidth),
8046 isMaxHeight = o.maxHeight && (o.maxHeight < newHeight),
8047 isMinWidth = o.minWidth && (o.minWidth > newWidth),
8048 isMinHeight = o.minHeight && (o.minHeight > newHeight);
8065 if (/^(se|s|e)$/.test(a)) {
8066 that.size.width = newWidth;
8067 that.size.height = newHeight;
8068 } else if (/^(ne)$/.test(a)) {
8069 that.size.width = newWidth;
8070 that.size.height = newHeight;
8071 that.position.top = op.top - oy;
8072 } else if (/^(sw)$/.test(a)) {
8073 that.size.width = newWidth;
8074 that.size.height = newHeight;
8075 that.position.left = op.left - ox;
8077 if ( newHeight - gridY <= 0 || newWidth - gridX <= 0) {
8078 outerDimensions = that._getPaddingPlusBorderDimensions( this );
8081 if ( newHeight - gridY > 0 ) {
8082 that.size.height = newHeight;
8083 that.position.top = op.top - oy;
8085 newHeight = gridY - outerDimensions.height;
8086 that.size.height = newHeight;
8087 that.position.top = op.top + os.height - newHeight;
8089 if ( newWidth - gridX > 0 ) {
8090 that.size.width = newWidth;
8091 that.position.left = op.left - ox;
8093 newWidth = gridY - outerDimensions.height;
8094 that.size.width = newWidth;
8095 that.position.left = op.left + os.width - newWidth;
8102 var resizable = $.ui.resizable;
8106 * jQuery UI Dialog 1.11.2
8107 * http://jqueryui.com
8109 * Copyright 2014 jQuery Foundation and other contributors
8110 * Released under the MIT license.
8111 * http://jquery.org/license
8113 * http://api.jqueryui.com/dialog/
8117 var dialog = $.widget( "ui.dialog", {
8123 closeOnEscape: true,
8139 // Ensure the titlebar is always visible
8140 using: function( pos ) {
8141 var topOffset = $( this ).css( pos ).offset().top;
8142 if ( topOffset < 0 ) {
8143 $( this ).css( "top", pos.top - topOffset );
8165 sizeRelatedOptions: {
8175 resizableRelatedOptions: {
8182 _create: function() {
8183 this.originalCss = {
8184 display: this.element[ 0 ].style.display,
8185 width: this.element[ 0 ].style.width,
8186 minHeight: this.element[ 0 ].style.minHeight,
8187 maxHeight: this.element[ 0 ].style.maxHeight,
8188 height: this.element[ 0 ].style.height
8190 this.originalPosition = {
8191 parent: this.element.parent(),
8192 index: this.element.parent().children().index( this.element )
8194 this.originalTitle = this.element.attr( "title" );
8195 this.options.title = this.options.title || this.originalTitle;
8197 this._createWrapper();
8201 .removeAttr( "title" )
8202 .addClass( "ui-dialog-content ui-widget-content" )
8203 .appendTo( this.uiDialog );
8205 this._createTitlebar();
8206 this._createButtonPane();
8208 if ( this.options.draggable && $.fn.draggable ) {
8209 this._makeDraggable();
8211 if ( this.options.resizable && $.fn.resizable ) {
8212 this._makeResizable();
8215 this._isOpen = false;
8221 if ( this.options.autoOpen ) {
8226 _appendTo: function() {
8227 var element = this.options.appendTo;
8228 if ( element && (element.jquery || element.nodeType) ) {
8229 return $( element );
8231 return this.document.find( element || "body" ).eq( 0 );
8234 _destroy: function() {
8236 originalPosition = this.originalPosition;
8238 this._destroyOverlay();
8242 .removeClass( "ui-dialog-content ui-widget-content" )
8243 .css( this.originalCss )
8244 // Without detaching first, the following becomes really slow
8247 this.uiDialog.stop( true, true ).remove();
8249 if ( this.originalTitle ) {
8250 this.element.attr( "title", this.originalTitle );
8253 next = originalPosition.parent.children().eq( originalPosition.index );
8254 // Don't try to place the dialog next to itself (#8613)
8255 if ( next.length && next[ 0 ] !== this.element[ 0 ] ) {
8256 next.before( this.element );
8258 originalPosition.parent.append( this.element );
8262 widget: function() {
8263 return this.uiDialog;
8269 close: function( event ) {
8273 if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) {
8277 this._isOpen = false;
8278 this._focusedElement = null;
8279 this._destroyOverlay();
8280 this._untrackInstance();
8282 if ( !this.opener.filter( ":focusable" ).focus().length ) {
8285 // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
8287 activeElement = this.document[ 0 ].activeElement;
8289 // Support: IE9, IE10
8290 // If the <body> is blurred, IE will switch windows, see #4520
8291 if ( activeElement && activeElement.nodeName.toLowerCase() !== "body" ) {
8293 // Hiding a focused element doesn't trigger blur in WebKit
8294 // so in case we have nothing to focus on, explicitly blur the active element
8295 // https://bugs.webkit.org/show_bug.cgi?id=47182
8296 $( activeElement ).blur();
8298 } catch ( error ) {}
8301 this._hide( this.uiDialog, this.options.hide, function() {
8302 that._trigger( "close", event );
8306 isOpen: function() {
8307 return this._isOpen;
8310 moveToTop: function() {
8314 _moveToTop: function( event, silent ) {
8316 zIndicies = this.uiDialog.siblings( ".ui-front:visible" ).map(function() {
8317 return +$( this ).css( "z-index" );
8319 zIndexMax = Math.max.apply( null, zIndicies );
8321 if ( zIndexMax >= +this.uiDialog.css( "z-index" ) ) {
8322 this.uiDialog.css( "z-index", zIndexMax + 1 );
8326 if ( moved && !silent ) {
8327 this._trigger( "focus", event );
8334 if ( this._isOpen ) {
8335 if ( this._moveToTop() ) {
8336 this._focusTabbable();
8341 this._isOpen = true;
8342 this.opener = $( this.document[ 0 ].activeElement );
8346 this._createOverlay();
8347 this._moveToTop( null, true );
8349 // Ensure the overlay is moved to the top with the dialog, but only when
8350 // opening. The overlay shouldn't move after the dialog is open so that
8351 // modeless dialogs opened after the modal dialog stack properly.
8352 if ( this.overlay ) {
8353 this.overlay.css( "z-index", this.uiDialog.css( "z-index" ) - 1 );
8356 this._show( this.uiDialog, this.options.show, function() {
8357 that._focusTabbable();
8358 that._trigger( "focus" );
8361 // Track the dialog immediately upon openening in case a focus event
8362 // somehow occurs outside of the dialog before an element inside the
8363 // dialog is focused (#10152)
8364 this._makeFocusTarget();
8366 this._trigger( "open" );
8369 _focusTabbable: function() {
8370 // Set focus to the first match:
8371 // 1. An element that was focused previously
8372 // 2. First element inside the dialog matching [autofocus]
8373 // 3. Tabbable element inside the content element
8374 // 4. Tabbable element inside the buttonpane
8375 // 5. The close button
8376 // 6. The dialog itself
8377 var hasFocus = this._focusedElement;
8379 hasFocus = this.element.find( "[autofocus]" );
8381 if ( !hasFocus.length ) {
8382 hasFocus = this.element.find( ":tabbable" );
8384 if ( !hasFocus.length ) {
8385 hasFocus = this.uiDialogButtonPane.find( ":tabbable" );
8387 if ( !hasFocus.length ) {
8388 hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" );
8390 if ( !hasFocus.length ) {
8391 hasFocus = this.uiDialog;
8393 hasFocus.eq( 0 ).focus();
8396 _keepFocus: function( event ) {
8397 function checkFocus() {
8398 var activeElement = this.document[0].activeElement,
8399 isActive = this.uiDialog[0] === activeElement ||
8400 $.contains( this.uiDialog[0], activeElement );
8402 this._focusTabbable();
8405 event.preventDefault();
8406 checkFocus.call( this );
8408 // IE <= 8 doesn't prevent moving focus even with event.preventDefault()
8409 // so we check again later
8410 this._delay( checkFocus );
8413 _createWrapper: function() {
8414 this.uiDialog = $("<div>")
8415 .addClass( "ui-dialog ui-widget ui-widget-content ui-corner-all ui-front " +
8416 this.options.dialogClass )
8419 // Setting tabIndex makes the div focusable
8423 .appendTo( this._appendTo() );
8425 this._on( this.uiDialog, {
8426 keydown: function( event ) {
8427 if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
8428 event.keyCode === $.ui.keyCode.ESCAPE ) {
8429 event.preventDefault();
8430 this.close( event );
8434 // prevent tabbing out of dialogs
8435 if ( event.keyCode !== $.ui.keyCode.TAB || event.isDefaultPrevented() ) {
8438 var tabbables = this.uiDialog.find( ":tabbable" ),
8439 first = tabbables.filter( ":first" ),
8440 last = tabbables.filter( ":last" );
8442 if ( ( event.target === last[0] || event.target === this.uiDialog[0] ) && !event.shiftKey ) {
8443 this._delay(function() {
8446 event.preventDefault();
8447 } else if ( ( event.target === first[0] || event.target === this.uiDialog[0] ) && event.shiftKey ) {
8448 this._delay(function() {
8451 event.preventDefault();
8454 mousedown: function( event ) {
8455 if ( this._moveToTop( event ) ) {
8456 this._focusTabbable();
8461 // We assume that any existing aria-describedby attribute means
8462 // that the dialog content is marked up properly
8463 // otherwise we brute force the content as the description
8464 if ( !this.element.find( "[aria-describedby]" ).length ) {
8465 this.uiDialog.attr({
8466 "aria-describedby": this.element.uniqueId().attr( "id" )
8471 _createTitlebar: function() {
8474 this.uiDialogTitlebar = $( "<div>" )
8475 .addClass( "ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix" )
8476 .prependTo( this.uiDialog );
8477 this._on( this.uiDialogTitlebar, {
8478 mousedown: function( event ) {
8479 // Don't prevent click on close button (#8838)
8480 // Focusing a dialog that is partially scrolled out of view
8481 // causes the browser to scroll it into view, preventing the click event
8482 if ( !$( event.target ).closest( ".ui-dialog-titlebar-close" ) ) {
8483 // Dialog isn't getting focus when dragging (#8063)
8484 this.uiDialog.focus();
8490 // Use type="button" to prevent enter keypresses in textboxes from closing the
8491 // dialog in IE (#9312)
8492 this.uiDialogTitlebarClose = $( "<button type='button'></button>" )
8494 label: this.options.closeText,
8496 primary: "ui-icon-closethick"
8500 .addClass( "ui-dialog-titlebar-close" )
8501 .appendTo( this.uiDialogTitlebar );
8502 this._on( this.uiDialogTitlebarClose, {
8503 click: function( event ) {
8504 event.preventDefault();
8505 this.close( event );
8509 uiDialogTitle = $( "<span>" )
8511 .addClass( "ui-dialog-title" )
8512 .prependTo( this.uiDialogTitlebar );
8513 this._title( uiDialogTitle );
8515 this.uiDialog.attr({
8516 "aria-labelledby": uiDialogTitle.attr( "id" )
8520 _title: function( title ) {
8521 if ( !this.options.title ) {
8522 title.html( " " );
8524 title.text( this.options.title );
8527 _createButtonPane: function() {
8528 this.uiDialogButtonPane = $( "<div>" )
8529 .addClass( "ui-dialog-buttonpane ui-widget-content ui-helper-clearfix" );
8531 this.uiButtonSet = $( "<div>" )
8532 .addClass( "ui-dialog-buttonset" )
8533 .appendTo( this.uiDialogButtonPane );
8535 this._createButtons();
8538 _createButtons: function() {
8540 buttons = this.options.buttons;
8542 // if we already have a button pane, remove it
8543 this.uiDialogButtonPane.remove();
8544 this.uiButtonSet.empty();
8546 if ( $.isEmptyObject( buttons ) || ($.isArray( buttons ) && !buttons.length) ) {
8547 this.uiDialog.removeClass( "ui-dialog-buttons" );
8551 $.each( buttons, function( name, props ) {
8552 var click, buttonOptions;
8553 props = $.isFunction( props ) ?
8554 { click: props, text: name } :
8556 // Default to a non-submitting button
8557 props = $.extend( { type: "button" }, props );
8558 // Change the context for the click callback to be the main element
8559 click = props.click;
8560 props.click = function() {
8561 click.apply( that.element[ 0 ], arguments );
8565 text: props.showText
8568 delete props.showText;
8569 $( "<button></button>", props )
8570 .button( buttonOptions )
8571 .appendTo( that.uiButtonSet );
8573 this.uiDialog.addClass( "ui-dialog-buttons" );
8574 this.uiDialogButtonPane.appendTo( this.uiDialog );
8577 _makeDraggable: function() {
8579 options = this.options;
8581 function filteredUi( ui ) {
8583 position: ui.position,
8588 this.uiDialog.draggable({
8589 cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
8590 handle: ".ui-dialog-titlebar",
8591 containment: "document",
8592 start: function( event, ui ) {
8593 $( this ).addClass( "ui-dialog-dragging" );
8594 that._blockFrames();
8595 that._trigger( "dragStart", event, filteredUi( ui ) );
8597 drag: function( event, ui ) {
8598 that._trigger( "drag", event, filteredUi( ui ) );
8600 stop: function( event, ui ) {
8601 var left = ui.offset.left - that.document.scrollLeft(),
8602 top = ui.offset.top - that.document.scrollTop();
8604 options.position = {
8606 at: "left" + (left >= 0 ? "+" : "") + left + " " +
8607 "top" + (top >= 0 ? "+" : "") + top,
8610 $( this ).removeClass( "ui-dialog-dragging" );
8611 that._unblockFrames();
8612 that._trigger( "dragStop", event, filteredUi( ui ) );
8617 _makeResizable: function() {
8619 options = this.options,
8620 handles = options.resizable,
8621 // .ui-resizable has position: relative defined in the stylesheet
8622 // but dialogs have to use absolute or fixed positioning
8623 position = this.uiDialog.css("position"),
8624 resizeHandles = typeof handles === "string" ?
8626 "n,e,s,w,se,sw,ne,nw";
8628 function filteredUi( ui ) {
8630 originalPosition: ui.originalPosition,
8631 originalSize: ui.originalSize,
8632 position: ui.position,
8637 this.uiDialog.resizable({
8638 cancel: ".ui-dialog-content",
8639 containment: "document",
8640 alsoResize: this.element,
8641 maxWidth: options.maxWidth,
8642 maxHeight: options.maxHeight,
8643 minWidth: options.minWidth,
8644 minHeight: this._minHeight(),
8645 handles: resizeHandles,
8646 start: function( event, ui ) {
8647 $( this ).addClass( "ui-dialog-resizing" );
8648 that._blockFrames();
8649 that._trigger( "resizeStart", event, filteredUi( ui ) );
8651 resize: function( event, ui ) {
8652 that._trigger( "resize", event, filteredUi( ui ) );
8654 stop: function( event, ui ) {
8655 var offset = that.uiDialog.offset(),
8656 left = offset.left - that.document.scrollLeft(),
8657 top = offset.top - that.document.scrollTop();
8659 options.height = that.uiDialog.height();
8660 options.width = that.uiDialog.width();
8661 options.position = {
8663 at: "left" + (left >= 0 ? "+" : "") + left + " " +
8664 "top" + (top >= 0 ? "+" : "") + top,
8667 $( this ).removeClass( "ui-dialog-resizing" );
8668 that._unblockFrames();
8669 that._trigger( "resizeStop", event, filteredUi( ui ) );
8672 .css( "position", position );
8675 _trackFocus: function() {
8676 this._on( this.widget(), {
8677 focusin: function( event ) {
8678 this._makeFocusTarget();
8679 this._focusedElement = $( event.target );
8684 _makeFocusTarget: function() {
8685 this._untrackInstance();
8686 this._trackingInstances().unshift( this );
8689 _untrackInstance: function() {
8690 var instances = this._trackingInstances(),
8691 exists = $.inArray( this, instances );
8692 if ( exists !== -1 ) {
8693 instances.splice( exists, 1 );
8697 _trackingInstances: function() {
8698 var instances = this.document.data( "ui-dialog-instances" );
8701 this.document.data( "ui-dialog-instances", instances );
8706 _minHeight: function() {
8707 var options = this.options;
8709 return options.height === "auto" ?
8711 Math.min( options.minHeight, options.height );
8714 _position: function() {
8715 // Need to show the dialog to get the actual offset in the position plugin
8716 var isVisible = this.uiDialog.is( ":visible" );
8718 this.uiDialog.show();
8720 this.uiDialog.position( this.options.position );
8722 this.uiDialog.hide();
8726 _setOptions: function( options ) {
8729 resizableOptions = {};
8731 $.each( options, function( key, value ) {
8732 that._setOption( key, value );
8734 if ( key in that.sizeRelatedOptions ) {
8737 if ( key in that.resizableRelatedOptions ) {
8738 resizableOptions[ key ] = value;
8746 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
8747 this.uiDialog.resizable( "option", resizableOptions );
8751 _setOption: function( key, value ) {
8752 var isDraggable, isResizable,
8753 uiDialog = this.uiDialog;
8755 if ( key === "dialogClass" ) {
8757 .removeClass( this.options.dialogClass )
8761 if ( key === "disabled" ) {
8765 this._super( key, value );
8767 if ( key === "appendTo" ) {
8768 this.uiDialog.appendTo( this._appendTo() );
8771 if ( key === "buttons" ) {
8772 this._createButtons();
8775 if ( key === "closeText" ) {
8776 this.uiDialogTitlebarClose.button({
8777 // Ensure that we always pass a string
8782 if ( key === "draggable" ) {
8783 isDraggable = uiDialog.is( ":data(ui-draggable)" );
8784 if ( isDraggable && !value ) {
8785 uiDialog.draggable( "destroy" );
8788 if ( !isDraggable && value ) {
8789 this._makeDraggable();
8793 if ( key === "position" ) {
8797 if ( key === "resizable" ) {
8798 // currently resizable, becoming non-resizable
8799 isResizable = uiDialog.is( ":data(ui-resizable)" );
8800 if ( isResizable && !value ) {
8801 uiDialog.resizable( "destroy" );
8804 // currently resizable, changing handles
8805 if ( isResizable && typeof value === "string" ) {
8806 uiDialog.resizable( "option", "handles", value );
8809 // currently non-resizable, becoming resizable
8810 if ( !isResizable && value !== false ) {
8811 this._makeResizable();
8815 if ( key === "title" ) {
8816 this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) );
8821 // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
8822 // divs will both have width and height set, so we need to reset them
8823 var nonContentHeight, minContentHeight, maxContentHeight,
8824 options = this.options;
8826 // Reset content sizing
8827 this.element.show().css({
8834 if ( options.minWidth > options.width ) {
8835 options.width = options.minWidth;
8838 // reset wrapper sizing
8839 // determine the height of all the non-content elements
8840 nonContentHeight = this.uiDialog.css({
8842 width: options.width
8845 minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
8846 maxContentHeight = typeof options.maxHeight === "number" ?
8847 Math.max( 0, options.maxHeight - nonContentHeight ) :
8850 if ( options.height === "auto" ) {
8852 minHeight: minContentHeight,
8853 maxHeight: maxContentHeight,
8857 this.element.height( Math.max( 0, options.height - nonContentHeight ) );
8860 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
8861 this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
8865 _blockFrames: function() {
8866 this.iframeBlocks = this.document.find( "iframe" ).map(function() {
8867 var iframe = $( this );
8871 position: "absolute",
8872 width: iframe.outerWidth(),
8873 height: iframe.outerHeight()
8875 .appendTo( iframe.parent() )
8876 .offset( iframe.offset() )[0];
8880 _unblockFrames: function() {
8881 if ( this.iframeBlocks ) {
8882 this.iframeBlocks.remove();
8883 delete this.iframeBlocks;
8887 _allowInteraction: function( event ) {
8888 if ( $( event.target ).closest( ".ui-dialog" ).length ) {
8892 // TODO: Remove hack when datepicker implements
8893 // the .ui-front logic (#8989)
8894 return !!$( event.target ).closest( ".ui-datepicker" ).length;
8897 _createOverlay: function() {
8898 if ( !this.options.modal ) {
8902 // We use a delay in case the overlay is created from an
8903 // event that we're going to be cancelling (#2804)
8904 var isOpening = true;
8905 this._delay(function() {
8909 if ( !this.document.data( "ui-dialog-overlays" ) ) {
8911 // Prevent use of anchors and inputs
8912 // Using _on() for an event handler shared across many instances is
8913 // safe because the dialogs stack and must be closed in reverse order
8914 this._on( this.document, {
8915 focusin: function( event ) {
8920 if ( !this._allowInteraction( event ) ) {
8921 event.preventDefault();
8922 this._trackingInstances()[ 0 ]._focusTabbable();
8928 this.overlay = $( "<div>" )
8929 .addClass( "ui-widget-overlay ui-front" )
8930 .appendTo( this._appendTo() );
8931 this._on( this.overlay, {
8932 mousedown: "_keepFocus"
8934 this.document.data( "ui-dialog-overlays",
8935 (this.document.data( "ui-dialog-overlays" ) || 0) + 1 );
8938 _destroyOverlay: function() {
8939 if ( !this.options.modal ) {
8943 if ( this.overlay ) {
8944 var overlays = this.document.data( "ui-dialog-overlays" ) - 1;
8948 .unbind( "focusin" )
8949 .removeData( "ui-dialog-overlays" );
8951 this.document.data( "ui-dialog-overlays", overlays );
8954 this.overlay.remove();
8955 this.overlay = null;
8962 * jQuery UI Droppable 1.11.2
8963 * http://jqueryui.com
8965 * Copyright 2014 jQuery Foundation and other contributors
8966 * Released under the MIT license.
8967 * http://jquery.org/license
8969 * http://api.jqueryui.com/droppable/
8973 $.widget( "ui.droppable", {
8975 widgetEventPrefix: "drop",
8983 tolerance: "intersect",
8992 _create: function() {
8998 this.isover = false;
9001 this.accept = $.isFunction( accept ) ? accept : function( d ) {
9002 return d.is( accept );
9005 this.proportions = function( /* valueToWrite */ ) {
9006 if ( arguments.length ) {
9007 // Store the droppable's proportions
9008 proportions = arguments[ 0 ];
9010 // Retrieve or derive the droppable's proportions
9011 return proportions ?
9014 width: this.element[ 0 ].offsetWidth,
9015 height: this.element[ 0 ].offsetHeight
9020 this._addToManager( o.scope );
9022 o.addClasses && this.element.addClass( "ui-droppable" );
9026 _addToManager: function( scope ) {
9027 // Add the reference and positions to the manager
9028 $.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || [];
9029 $.ui.ddmanager.droppables[ scope ].push( this );
9032 _splice: function( drop ) {
9034 for ( ; i < drop.length; i++ ) {
9035 if ( drop[ i ] === this ) {
9036 drop.splice( i, 1 );
9041 _destroy: function() {
9042 var drop = $.ui.ddmanager.droppables[ this.options.scope ];
9044 this._splice( drop );
9046 this.element.removeClass( "ui-droppable ui-droppable-disabled" );
9049 _setOption: function( key, value ) {
9051 if ( key === "accept" ) {
9052 this.accept = $.isFunction( value ) ? value : function( d ) {
9053 return d.is( value );
9055 } else if ( key === "scope" ) {
9056 var drop = $.ui.ddmanager.droppables[ this.options.scope ];
9058 this._splice( drop );
9059 this._addToManager( value );
9062 this._super( key, value );
9065 _activate: function( event ) {
9066 var draggable = $.ui.ddmanager.current;
9067 if ( this.options.activeClass ) {
9068 this.element.addClass( this.options.activeClass );
9071 this._trigger( "activate", event, this.ui( draggable ) );
9075 _deactivate: function( event ) {
9076 var draggable = $.ui.ddmanager.current;
9077 if ( this.options.activeClass ) {
9078 this.element.removeClass( this.options.activeClass );
9081 this._trigger( "deactivate", event, this.ui( draggable ) );
9085 _over: function( event ) {
9087 var draggable = $.ui.ddmanager.current;
9089 // Bail if draggable and droppable are same element
9090 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
9094 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
9095 if ( this.options.hoverClass ) {
9096 this.element.addClass( this.options.hoverClass );
9098 this._trigger( "over", event, this.ui( draggable ) );
9103 _out: function( event ) {
9105 var draggable = $.ui.ddmanager.current;
9107 // Bail if draggable and droppable are same element
9108 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
9112 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
9113 if ( this.options.hoverClass ) {
9114 this.element.removeClass( this.options.hoverClass );
9116 this._trigger( "out", event, this.ui( draggable ) );
9121 _drop: function( event, custom ) {
9123 var draggable = custom || $.ui.ddmanager.current,
9124 childrenIntersection = false;
9126 // Bail if draggable and droppable are same element
9127 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
9131 this.element.find( ":data(ui-droppable)" ).not( ".ui-draggable-dragging" ).each(function() {
9132 var inst = $( this ).droppable( "instance" );
9134 inst.options.greedy &&
9135 !inst.options.disabled &&
9136 inst.options.scope === draggable.options.scope &&
9137 inst.accept.call( inst.element[ 0 ], ( draggable.currentItem || draggable.element ) ) &&
9138 $.ui.intersect( draggable, $.extend( inst, { offset: inst.element.offset() } ), inst.options.tolerance, event )
9139 ) { childrenIntersection = true; return false; }
9141 if ( childrenIntersection ) {
9145 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
9146 if ( this.options.activeClass ) {
9147 this.element.removeClass( this.options.activeClass );
9149 if ( this.options.hoverClass ) {
9150 this.element.removeClass( this.options.hoverClass );
9152 this._trigger( "drop", event, this.ui( draggable ) );
9153 return this.element;
9162 draggable: ( c.currentItem || c.element ),
9164 position: c.position,
9165 offset: c.positionAbs
9171 $.ui.intersect = (function() {
9172 function isOverAxis( x, reference, size ) {
9173 return ( x >= reference ) && ( x < ( reference + size ) );
9176 return function( draggable, droppable, toleranceMode, event ) {
9178 if ( !droppable.offset ) {
9182 var x1 = ( draggable.positionAbs || draggable.position.absolute ).left + draggable.margins.left,
9183 y1 = ( draggable.positionAbs || draggable.position.absolute ).top + draggable.margins.top,
9184 x2 = x1 + draggable.helperProportions.width,
9185 y2 = y1 + draggable.helperProportions.height,
9186 l = droppable.offset.left,
9187 t = droppable.offset.top,
9188 r = l + droppable.proportions().width,
9189 b = t + droppable.proportions().height;
9191 switch ( toleranceMode ) {
9193 return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b );
9195 return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half
9196 x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half
9197 t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half
9198 y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half
9200 return isOverAxis( event.pageY, t, droppable.proportions().height ) && isOverAxis( event.pageX, l, droppable.proportions().width );
9203 ( y1 >= t && y1 <= b ) || // Top edge touching
9204 ( y2 >= t && y2 <= b ) || // Bottom edge touching
9205 ( y1 < t && y2 > b ) // Surrounded vertically
9207 ( x1 >= l && x1 <= r ) || // Left edge touching
9208 ( x2 >= l && x2 <= r ) || // Right edge touching
9209 ( x1 < l && x2 > r ) // Surrounded horizontally
9218 This manager tracks offsets of draggables and droppables
9222 droppables: { "default": [] },
9223 prepareOffsets: function( t, event ) {
9226 m = $.ui.ddmanager.droppables[ t.options.scope ] || [],
9227 type = event ? event.type : null, // workaround for #2317
9228 list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack();
9230 droppablesLoop: for ( i = 0; i < m.length; i++ ) {
9232 // No disabled and non-accepted
9233 if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ], ( t.currentItem || t.element ) ) ) ) {
9237 // Filter out elements in the current dragged item
9238 for ( j = 0; j < list.length; j++ ) {
9239 if ( list[ j ] === m[ i ].element[ 0 ] ) {
9240 m[ i ].proportions().height = 0;
9241 continue droppablesLoop;
9245 m[ i ].visible = m[ i ].element.css( "display" ) !== "none";
9246 if ( !m[ i ].visible ) {
9250 // Activate the droppable if used directly from draggables
9251 if ( type === "mousedown" ) {
9252 m[ i ]._activate.call( m[ i ], event );
9255 m[ i ].offset = m[ i ].element.offset();
9256 m[ i ].proportions({ width: m[ i ].element[ 0 ].offsetWidth, height: m[ i ].element[ 0 ].offsetHeight });
9261 drop: function( draggable, event ) {
9263 var dropped = false;
9264 // Create a copy of the droppables in case the list changes during the drop (#9116)
9265 $.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() {
9267 if ( !this.options ) {
9270 if ( !this.options.disabled && this.visible && $.ui.intersect( draggable, this, this.options.tolerance, event ) ) {
9271 dropped = this._drop.call( this, event ) || dropped;
9274 if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
9276 this.isover = false;
9277 this._deactivate.call( this, event );
9284 dragStart: function( draggable, event ) {
9285 // Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003)
9286 draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() {
9287 if ( !draggable.options.refreshPositions ) {
9288 $.ui.ddmanager.prepareOffsets( draggable, event );
9292 drag: function( draggable, event ) {
9294 // If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
9295 if ( draggable.options.refreshPositions ) {
9296 $.ui.ddmanager.prepareOffsets( draggable, event );
9299 // Run through all droppables and check their positions based on specific tolerance options
9300 $.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() {
9302 if ( this.options.disabled || this.greedyChild || !this.visible ) {
9306 var parentInstance, scope, parent,
9307 intersects = $.ui.intersect( draggable, this, this.options.tolerance, event ),
9308 c = !intersects && this.isover ? "isout" : ( intersects && !this.isover ? "isover" : null );
9313 if ( this.options.greedy ) {
9314 // find droppable parents with same scope
9315 scope = this.options.scope;
9316 parent = this.element.parents( ":data(ui-droppable)" ).filter(function() {
9317 return $( this ).droppable( "instance" ).options.scope === scope;
9320 if ( parent.length ) {
9321 parentInstance = $( parent[ 0 ] ).droppable( "instance" );
9322 parentInstance.greedyChild = ( c === "isover" );
9326 // we just moved into a greedy child
9327 if ( parentInstance && c === "isover" ) {
9328 parentInstance.isover = false;
9329 parentInstance.isout = true;
9330 parentInstance._out.call( parentInstance, event );
9334 this[c === "isout" ? "isover" : "isout"] = false;
9335 this[c === "isover" ? "_over" : "_out"].call( this, event );
9337 // we just moved out of a greedy child
9338 if ( parentInstance && c === "isout" ) {
9339 parentInstance.isout = false;
9340 parentInstance.isover = true;
9341 parentInstance._over.call( parentInstance, event );
9346 dragStop: function( draggable, event ) {
9347 draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" );
9348 // Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003)
9349 if ( !draggable.options.refreshPositions ) {
9350 $.ui.ddmanager.prepareOffsets( draggable, event );
9355 var droppable = $.ui.droppable;
9359 * jQuery UI Effects 1.11.2
9360 * http://jqueryui.com
9362 * Copyright 2014 jQuery Foundation and other contributors
9363 * Released under the MIT license.
9364 * http://jquery.org/license
9366 * http://api.jqueryui.com/category/effects-core/
9370 var dataSpace = "ui-effects-",
9372 // Create a local jQuery because jQuery Color relies on it and the
9373 // global may not exist with AMD and a custom build (#10199)
9381 * jQuery Color Animations v2.1.2
9382 * https://github.com/jquery/jquery-color
9384 * Copyright 2014 jQuery Foundation and other contributors
9385 * Released under the MIT license.
9386 * http://jquery.org/license
9388 * Date: Wed Jan 16 08:47:09 2013 -0600
9390 (function( jQuery, undefined ) {
9392 var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
9394 // plusequals test for += 100 -= 100
9395 rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
9396 // a set of RE's that can match strings and generate color tuples.
9398 re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
9399 parse: function( execResult ) {
9408 re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
9409 parse: function( execResult ) {
9411 execResult[ 1 ] * 2.55,
9412 execResult[ 2 ] * 2.55,
9413 execResult[ 3 ] * 2.55,
9418 // this regex ignores A-F because it's compared against an already lowercased string
9419 re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
9420 parse: function( execResult ) {
9422 parseInt( execResult[ 1 ], 16 ),
9423 parseInt( execResult[ 2 ], 16 ),
9424 parseInt( execResult[ 3 ], 16 )
9428 // this regex ignores A-F because it's compared against an already lowercased string
9429 re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
9430 parse: function( execResult ) {
9432 parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
9433 parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
9434 parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
9438 re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
9440 parse: function( execResult ) {
9443 execResult[ 2 ] / 100,
9444 execResult[ 3 ] / 100,
9451 color = jQuery.Color = function( color, green, blue, alpha ) {
9452 return new jQuery.Color.fn.parse( color, green, blue, alpha );
9502 support = color.support = {},
9504 // element for support tests
9505 supportElem = jQuery( "<p>" )[ 0 ],
9507 // colors = jQuery.Color.names
9510 // local aliases of functions called often
9513 // determine rgba support immediately
9514 supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
9515 support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
9517 // define cache name and alpha properties
9518 // for rgba and hsla spaces
9519 each( spaces, function( spaceName, space ) {
9520 space.cache = "_" + spaceName;
9521 space.props.alpha = {
9528 function clamp( value, prop, allowEmpty ) {
9529 var type = propTypes[ prop.type ] || {};
9531 if ( value == null ) {
9532 return (allowEmpty || !prop.def) ? null : prop.def;
9535 // ~~ is an short way of doing floor for positive numbers
9536 value = type.floor ? ~~value : parseFloat( value );
9538 // IE will pass in empty strings as value for alpha,
9539 // which will hit this case
9540 if ( isNaN( value ) ) {
9545 // we add mod before modding to make sure that negatives values
9546 // get converted properly: -10 -> 350
9547 return (value + type.mod) % type.mod;
9550 // for now all property types without mod have min and max
9551 return 0 > value ? 0 : type.max < value ? type.max : value;
9554 function stringParse( string ) {
9556 rgba = inst._rgba = [];
9558 string = string.toLowerCase();
9560 each( stringParsers, function( i, parser ) {
9562 match = parser.re.exec( string ),
9563 values = match && parser.parse( match ),
9564 spaceName = parser.space || "rgba";
9567 parsed = inst[ spaceName ]( values );
9569 // if this was an rgba parse the assignment might happen twice
9571 inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
9572 rgba = inst._rgba = parsed._rgba;
9574 // exit each( stringParsers ) here because we matched
9579 // Found a stringParser that handled it
9580 if ( rgba.length ) {
9582 // if this came from a parsed string, force "transparent" when alpha is 0
9583 // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
9584 if ( rgba.join() === "0,0,0,0" ) {
9585 jQuery.extend( rgba, colors.transparent );
9591 return colors[ string ];
9594 color.fn = jQuery.extend( color.prototype, {
9595 parse: function( red, green, blue, alpha ) {
9596 if ( red === undefined ) {
9597 this._rgba = [ null, null, null, null ];
9600 if ( red.jquery || red.nodeType ) {
9601 red = jQuery( red ).css( green );
9606 type = jQuery.type( red ),
9607 rgba = this._rgba = [];
9609 // more than 1 argument specified - assume ( red, green, blue, alpha )
9610 if ( green !== undefined ) {
9611 red = [ red, green, blue, alpha ];
9615 if ( type === "string" ) {
9616 return this.parse( stringParse( red ) || colors._default );
9619 if ( type === "array" ) {
9620 each( spaces.rgba.props, function( key, prop ) {
9621 rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
9626 if ( type === "object" ) {
9627 if ( red instanceof color ) {
9628 each( spaces, function( spaceName, space ) {
9629 if ( red[ space.cache ] ) {
9630 inst[ space.cache ] = red[ space.cache ].slice();
9634 each( spaces, function( spaceName, space ) {
9635 var cache = space.cache;
9636 each( space.props, function( key, prop ) {
9638 // if the cache doesn't exist, and we know how to convert
9639 if ( !inst[ cache ] && space.to ) {
9641 // if the value was null, we don't need to copy it
9642 // if the key was alpha, we don't need to copy it either
9643 if ( key === "alpha" || red[ key ] == null ) {
9646 inst[ cache ] = space.to( inst._rgba );
9649 // this is the only case where we allow nulls for ALL properties.
9650 // call clamp with alwaysAllowEmpty
9651 inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
9654 // everything defined but alpha?
9655 if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
9656 // use the default of 1
9657 inst[ cache ][ 3 ] = 1;
9659 inst._rgba = space.from( inst[ cache ] );
9667 is: function( compare ) {
9668 var is = color( compare ),
9672 each( spaces, function( _, space ) {
9674 isCache = is[ space.cache ];
9676 localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
9677 each( space.props, function( _, prop ) {
9678 if ( isCache[ prop.idx ] != null ) {
9679 same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
9688 _space: function() {
9691 each( spaces, function( spaceName, space ) {
9692 if ( inst[ space.cache ] ) {
9693 used.push( spaceName );
9698 transition: function( other, distance ) {
9699 var end = color( other ),
9700 spaceName = end._space(),
9701 space = spaces[ spaceName ],
9702 startColor = this.alpha() === 0 ? color( "transparent" ) : this,
9703 start = startColor[ space.cache ] || space.to( startColor._rgba ),
9704 result = start.slice();
9706 end = end[ space.cache ];
9707 each( space.props, function( key, prop ) {
9708 var index = prop.idx,
9709 startValue = start[ index ],
9710 endValue = end[ index ],
9711 type = propTypes[ prop.type ] || {};
9713 // if null, don't override start value
9714 if ( endValue === null ) {
9717 // if null - use end
9718 if ( startValue === null ) {
9719 result[ index ] = endValue;
9722 if ( endValue - startValue > type.mod / 2 ) {
9723 startValue += type.mod;
9724 } else if ( startValue - endValue > type.mod / 2 ) {
9725 startValue -= type.mod;
9728 result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
9731 return this[ spaceName ]( result );
9733 blend: function( opaque ) {
9734 // if we are already opaque - return ourself
9735 if ( this._rgba[ 3 ] === 1 ) {
9739 var rgb = this._rgba.slice(),
9741 blend = color( opaque )._rgba;
9743 return color( jQuery.map( rgb, function( v, i ) {
9744 return ( 1 - a ) * blend[ i ] + a * v;
9747 toRgbaString: function() {
9748 var prefix = "rgba(",
9749 rgba = jQuery.map( this._rgba, function( v, i ) {
9750 return v == null ? ( i > 2 ? 1 : 0 ) : v;
9753 if ( rgba[ 3 ] === 1 ) {
9758 return prefix + rgba.join() + ")";
9760 toHslaString: function() {
9761 var prefix = "hsla(",
9762 hsla = jQuery.map( this.hsla(), function( v, i ) {
9769 v = Math.round( v * 100 ) + "%";
9774 if ( hsla[ 3 ] === 1 ) {
9778 return prefix + hsla.join() + ")";
9780 toHexString: function( includeAlpha ) {
9781 var rgba = this._rgba.slice(),
9784 if ( includeAlpha ) {
9785 rgba.push( ~~( alpha * 255 ) );
9788 return "#" + jQuery.map( rgba, function( v ) {
9790 // default to 0 when nulls exist
9791 v = ( v || 0 ).toString( 16 );
9792 return v.length === 1 ? "0" + v : v;
9795 toString: function() {
9796 return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
9799 color.fn.parse.prototype = color.fn;
9801 // hsla conversions adapted from:
9802 // https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
9804 function hue2rgb( p, q, h ) {
9807 return p + ( q - p ) * h * 6;
9813 return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6;
9818 spaces.hsla.to = function( rgba ) {
9819 if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
9820 return [ null, null, null, rgba[ 3 ] ];
9822 var r = rgba[ 0 ] / 255,
9823 g = rgba[ 1 ] / 255,
9824 b = rgba[ 2 ] / 255,
9826 max = Math.max( r, g, b ),
9827 min = Math.min( r, g, b ),
9833 if ( min === max ) {
9835 } else if ( r === max ) {
9836 h = ( 60 * ( g - b ) / diff ) + 360;
9837 } else if ( g === max ) {
9838 h = ( 60 * ( b - r ) / diff ) + 120;
9840 h = ( 60 * ( r - g ) / diff ) + 240;
9843 // chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
9844 // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
9847 } else if ( l <= 0.5 ) {
9850 s = diff / ( 2 - add );
9852 return [ Math.round(h) % 360, s, l, a == null ? 1 : a ];
9855 spaces.hsla.from = function( hsla ) {
9856 if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
9857 return [ null, null, null, hsla[ 3 ] ];
9859 var h = hsla[ 0 ] / 360,
9863 q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
9867 Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
9868 Math.round( hue2rgb( p, q, h ) * 255 ),
9869 Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
9874 each( spaces, function( spaceName, space ) {
9875 var props = space.props,
9876 cache = space.cache,
9880 // makes rgba() and hsla()
9881 color.fn[ spaceName ] = function( value ) {
9883 // generate a cache for this space if it doesn't exist
9884 if ( to && !this[ cache ] ) {
9885 this[ cache ] = to( this._rgba );
9887 if ( value === undefined ) {
9888 return this[ cache ].slice();
9892 type = jQuery.type( value ),
9893 arr = ( type === "array" || type === "object" ) ? value : arguments,
9894 local = this[ cache ].slice();
9896 each( props, function( key, prop ) {
9897 var val = arr[ type === "object" ? key : prop.idx ];
9898 if ( val == null ) {
9899 val = local[ prop.idx ];
9901 local[ prop.idx ] = clamp( val, prop );
9905 ret = color( from( local ) );
9906 ret[ cache ] = local;
9909 return color( local );
9913 // makes red() green() blue() alpha() hue() saturation() lightness()
9914 each( props, function( key, prop ) {
9915 // alpha is included in more than one space
9916 if ( color.fn[ key ] ) {
9919 color.fn[ key ] = function( value ) {
9920 var vtype = jQuery.type( value ),
9921 fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
9922 local = this[ fn ](),
9923 cur = local[ prop.idx ],
9926 if ( vtype === "undefined" ) {
9930 if ( vtype === "function" ) {
9931 value = value.call( this, cur );
9932 vtype = jQuery.type( value );
9934 if ( value == null && prop.empty ) {
9937 if ( vtype === "string" ) {
9938 match = rplusequals.exec( value );
9940 value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
9943 local[ prop.idx ] = value;
9944 return this[ fn ]( local );
9949 // add cssHook and .fx.step function for each named hook.
9950 // accept a space separated string of properties
9951 color.hook = function( hook ) {
9952 var hooks = hook.split( " " );
9953 each( hooks, function( i, hook ) {
9954 jQuery.cssHooks[ hook ] = {
9955 set: function( elem, value ) {
9956 var parsed, curElem,
9957 backgroundColor = "";
9959 if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) {
9960 value = color( parsed || value );
9961 if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
9962 curElem = hook === "backgroundColor" ? elem.parentNode : elem;
9964 (backgroundColor === "" || backgroundColor === "transparent") &&
9965 curElem && curElem.style
9968 backgroundColor = jQuery.css( curElem, "backgroundColor" );
9969 curElem = curElem.parentNode;
9974 value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
9979 value = value.toRgbaString();
9982 elem.style[ hook ] = value;
9984 // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit'
9988 jQuery.fx.step[ hook ] = function( fx ) {
9989 if ( !fx.colorInit ) {
9990 fx.start = color( fx.elem, hook );
9991 fx.end = color( fx.end );
9992 fx.colorInit = true;
9994 jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
10000 color.hook( stepHooks );
10002 jQuery.cssHooks.borderColor = {
10003 expand: function( value ) {
10006 each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
10007 expanded[ "border" + part + "Color" ] = value;
10013 // Basic color names only.
10014 // Usage of any of the other color names requires adding yourself or including
10015 // jquery.color.svg-names.js.
10016 colors = jQuery.Color.names = {
10017 // 4.1. Basic color keywords
10021 fuchsia: "#ff00ff",
10035 // 4.2.3. "transparent" color keyword
10036 transparent: [ null, null, null, 0 ],
10038 _default: "#ffffff"
10043 /******************************************************************************/
10044 /****************************** CLASS ANIMATIONS ******************************/
10045 /******************************************************************************/
10048 var classAnimationActions = [ "add", "remove", "toggle" ],
10049 shorthandStyles = {
10061 $.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) {
10062 $.fx.step[ prop ] = function( fx ) {
10063 if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
10064 jQuery.style( fx.elem, prop, fx.end );
10070 function getElementStyles( elem ) {
10072 style = elem.ownerDocument.defaultView ?
10073 elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :
10077 if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
10078 len = style.length;
10080 key = style[ len ];
10081 if ( typeof style[ key ] === "string" ) {
10082 styles[ $.camelCase( key ) ] = style[ key ];
10085 // support: Opera, IE <9
10087 for ( key in style ) {
10088 if ( typeof style[ key ] === "string" ) {
10089 styles[ key ] = style[ key ];
10097 function styleDifference( oldStyle, newStyle ) {
10101 for ( name in newStyle ) {
10102 value = newStyle[ name ];
10103 if ( oldStyle[ name ] !== value ) {
10104 if ( !shorthandStyles[ name ] ) {
10105 if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
10106 diff[ name ] = value;
10115 // support: jQuery <1.8
10116 if ( !$.fn.addBack ) {
10117 $.fn.addBack = function( selector ) {
10118 return this.add( selector == null ?
10119 this.prevObject : this.prevObject.filter( selector )
10124 $.effects.animateClass = function( value, duration, easing, callback ) {
10125 var o = $.speed( duration, easing, callback );
10127 return this.queue( function() {
10128 var animated = $( this ),
10129 baseClass = animated.attr( "class" ) || "",
10131 allAnimations = o.children ? animated.find( "*" ).addBack() : animated;
10133 // map the animated objects to store the original styles.
10134 allAnimations = allAnimations.map(function() {
10135 var el = $( this );
10138 start: getElementStyles( this )
10142 // apply class change
10143 applyClassChange = function() {
10144 $.each( classAnimationActions, function(i, action) {
10145 if ( value[ action ] ) {
10146 animated[ action + "Class" ]( value[ action ] );
10150 applyClassChange();
10152 // map all animated objects again - calculate new styles and diff
10153 allAnimations = allAnimations.map(function() {
10154 this.end = getElementStyles( this.el[ 0 ] );
10155 this.diff = styleDifference( this.start, this.end );
10159 // apply original class
10160 animated.attr( "class", baseClass );
10162 // map all animated objects again - this time collecting a promise
10163 allAnimations = allAnimations.map(function() {
10164 var styleInfo = this,
10165 dfd = $.Deferred(),
10166 opts = $.extend({}, o, {
10168 complete: function() {
10169 dfd.resolve( styleInfo );
10173 this.el.animate( this.diff, opts );
10174 return dfd.promise();
10177 // once all animations have completed:
10178 $.when.apply( $, allAnimations.get() ).done(function() {
10180 // set the final class
10181 applyClassChange();
10183 // for each animated element,
10184 // clear all css properties that were animated
10185 $.each( arguments, function() {
10187 $.each( this.diff, function(key) {
10192 // this is guarnteed to be there if you use jQuery.speed()
10193 // it also handles dequeuing the next anim...
10194 o.complete.call( animated[ 0 ] );
10200 addClass: (function( orig ) {
10201 return function( classNames, speed, easing, callback ) {
10203 $.effects.animateClass.call( this,
10204 { add: classNames }, speed, easing, callback ) :
10205 orig.apply( this, arguments );
10207 })( $.fn.addClass ),
10209 removeClass: (function( orig ) {
10210 return function( classNames, speed, easing, callback ) {
10211 return arguments.length > 1 ?
10212 $.effects.animateClass.call( this,
10213 { remove: classNames }, speed, easing, callback ) :
10214 orig.apply( this, arguments );
10216 })( $.fn.removeClass ),
10218 toggleClass: (function( orig ) {
10219 return function( classNames, force, speed, easing, callback ) {
10220 if ( typeof force === "boolean" || force === undefined ) {
10222 // without speed parameter
10223 return orig.apply( this, arguments );
10225 return $.effects.animateClass.call( this,
10226 (force ? { add: classNames } : { remove: classNames }),
10227 speed, easing, callback );
10230 // without force parameter
10231 return $.effects.animateClass.call( this,
10232 { toggle: classNames }, force, speed, easing );
10235 })( $.fn.toggleClass ),
10237 switchClass: function( remove, add, speed, easing, callback) {
10238 return $.effects.animateClass.call( this, {
10241 }, speed, easing, callback );
10247 /******************************************************************************/
10248 /*********************************** EFFECTS **********************************/
10249 /******************************************************************************/
10253 $.extend( $.effects, {
10256 // Saves a set of properties in a data storage
10257 save: function( element, set ) {
10258 for ( var i = 0; i < set.length; i++ ) {
10259 if ( set[ i ] !== null ) {
10260 element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
10265 // Restores a set of previously saved properties from a data storage
10266 restore: function( element, set ) {
10268 for ( i = 0; i < set.length; i++ ) {
10269 if ( set[ i ] !== null ) {
10270 val = element.data( dataSpace + set[ i ] );
10271 // support: jQuery 1.6.2
10272 // http://bugs.jquery.com/ticket/9917
10273 // jQuery 1.6.2 incorrectly returns undefined for any falsy value.
10274 // We can't differentiate between "" and 0 here, so we just assume
10275 // empty string since it's likely to be a more common value...
10276 if ( val === undefined ) {
10279 element.css( set[ i ], val );
10284 setMode: function( el, mode ) {
10285 if (mode === "toggle") {
10286 mode = el.is( ":hidden" ) ? "show" : "hide";
10291 // Translates a [top,left] array into a baseline value
10292 // this should be a little more flexible in the future to handle a string & hash
10293 getBaseline: function( origin, original ) {
10295 switch ( origin[ 0 ] ) {
10296 case "top": y = 0; break;
10297 case "middle": y = 0.5; break;
10298 case "bottom": y = 1; break;
10299 default: y = origin[ 0 ] / original.height;
10301 switch ( origin[ 1 ] ) {
10302 case "left": x = 0; break;
10303 case "center": x = 0.5; break;
10304 case "right": x = 1; break;
10305 default: x = origin[ 1 ] / original.width;
10313 // Wraps the element around a wrapper that copies position properties
10314 createWrapper: function( element ) {
10316 // if the element is already wrapped, return it
10317 if ( element.parent().is( ".ui-effects-wrapper" )) {
10318 return element.parent();
10321 // wrap the element
10323 width: element.outerWidth(true),
10324 height: element.outerHeight(true),
10325 "float": element.css( "float" )
10327 wrapper = $( "<div></div>" )
10328 .addClass( "ui-effects-wrapper" )
10331 background: "transparent",
10336 // Store the size in case width/height are defined in % - Fixes #5245
10338 width: element.width(),
10339 height: element.height()
10341 active = document.activeElement;
10343 // support: Firefox
10344 // Firefox incorrectly exposes anonymous content
10345 // https://bugzilla.mozilla.org/show_bug.cgi?id=561664
10349 active = document.body;
10352 element.wrap( wrapper );
10354 // Fixes #7595 - Elements lose focus when wrapped.
10355 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
10356 $( active ).focus();
10359 wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element
10361 // transfer positioning properties to the wrapper
10362 if ( element.css( "position" ) === "static" ) {
10363 wrapper.css({ position: "relative" });
10364 element.css({ position: "relative" });
10367 position: element.css( "position" ),
10368 zIndex: element.css( "z-index" )
10370 $.each([ "top", "left", "bottom", "right" ], function(i, pos) {
10371 props[ pos ] = element.css( pos );
10372 if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
10373 props[ pos ] = "auto";
10377 position: "relative",
10386 return wrapper.css( props ).show();
10389 removeWrapper: function( element ) {
10390 var active = document.activeElement;
10392 if ( element.parent().is( ".ui-effects-wrapper" ) ) {
10393 element.parent().replaceWith( element );
10395 // Fixes #7595 - Elements lose focus when wrapped.
10396 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
10397 $( active ).focus();
10404 setTransition: function( element, list, factor, value ) {
10405 value = value || {};
10406 $.each( list, function( i, x ) {
10407 var unit = element.cssUnit( x );
10408 if ( unit[ 0 ] > 0 ) {
10409 value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
10416 // return an effect options object for the given parameters:
10417 function _normalizeArguments( effect, options, speed, callback ) {
10419 // allow passing all options as the first parameter
10420 if ( $.isPlainObject( effect ) ) {
10422 effect = effect.effect;
10425 // convert to an object
10426 effect = { effect: effect };
10428 // catch (effect, null, ...)
10429 if ( options == null ) {
10433 // catch (effect, callback)
10434 if ( $.isFunction( options ) ) {
10435 callback = options;
10440 // catch (effect, speed, ?)
10441 if ( typeof options === "number" || $.fx.speeds[ options ] ) {
10447 // catch (effect, options, callback)
10448 if ( $.isFunction( speed ) ) {
10453 // add options to effect
10455 $.extend( effect, options );
10458 speed = speed || options.duration;
10459 effect.duration = $.fx.off ? 0 :
10460 typeof speed === "number" ? speed :
10461 speed in $.fx.speeds ? $.fx.speeds[ speed ] :
10462 $.fx.speeds._default;
10464 effect.complete = callback || options.complete;
10469 function standardAnimationOption( option ) {
10470 // Valid standard speeds (nothing, number, named speed)
10471 if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) {
10475 // Invalid strings - treat as "normal" speed
10476 if ( typeof option === "string" && !$.effects.effect[ option ] ) {
10480 // Complete callback
10481 if ( $.isFunction( option ) ) {
10485 // Options hash (but not naming an effect)
10486 if ( typeof option === "object" && !option.effect ) {
10490 // Didn't match any standard API
10495 effect: function( /* effect, options, speed, callback */ ) {
10496 var args = _normalizeArguments.apply( this, arguments ),
10498 queue = args.queue,
10499 effectMethod = $.effects.effect[ args.effect ];
10501 if ( $.fx.off || !effectMethod ) {
10502 // delegate to the original method (e.g., .show()) if possible
10504 return this[ mode ]( args.duration, args.complete );
10506 return this.each( function() {
10507 if ( args.complete ) {
10508 args.complete.call( this );
10514 function run( next ) {
10515 var elem = $( this ),
10516 complete = args.complete,
10520 if ( $.isFunction( complete ) ) {
10521 complete.call( elem[0] );
10523 if ( $.isFunction( next ) ) {
10528 // If the element already has the correct final state, delegate to
10529 // the core methods so the internal tracking of "olddisplay" works.
10530 if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
10534 effectMethod.call( elem[0], args, done );
10538 return queue === false ? this.each( run ) : this.queue( queue || "fx", run );
10541 show: (function( orig ) {
10542 return function( option ) {
10543 if ( standardAnimationOption( option ) ) {
10544 return orig.apply( this, arguments );
10546 var args = _normalizeArguments.apply( this, arguments );
10547 args.mode = "show";
10548 return this.effect.call( this, args );
10553 hide: (function( orig ) {
10554 return function( option ) {
10555 if ( standardAnimationOption( option ) ) {
10556 return orig.apply( this, arguments );
10558 var args = _normalizeArguments.apply( this, arguments );
10559 args.mode = "hide";
10560 return this.effect.call( this, args );
10565 toggle: (function( orig ) {
10566 return function( option ) {
10567 if ( standardAnimationOption( option ) || typeof option === "boolean" ) {
10568 return orig.apply( this, arguments );
10570 var args = _normalizeArguments.apply( this, arguments );
10571 args.mode = "toggle";
10572 return this.effect.call( this, args );
10577 // helper functions
10578 cssUnit: function(key) {
10579 var style = this.css( key ),
10582 $.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
10583 if ( style.indexOf( unit ) > 0 ) {
10584 val = [ parseFloat( style ), unit ];
10593 /******************************************************************************/
10594 /*********************************** EASING ***********************************/
10595 /******************************************************************************/
10599 // based on easing equations from Robert Penner (http://www.robertpenner.com/easing)
10601 var baseEasings = {};
10603 $.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
10604 baseEasings[ name ] = function( p ) {
10605 return Math.pow( p, i + 2 );
10609 $.extend( baseEasings, {
10610 Sine: function( p ) {
10611 return 1 - Math.cos( p * Math.PI / 2 );
10613 Circ: function( p ) {
10614 return 1 - Math.sqrt( 1 - p * p );
10616 Elastic: function( p ) {
10617 return p === 0 || p === 1 ? p :
10618 -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 );
10620 Back: function( p ) {
10621 return p * p * ( 3 * p - 2 );
10623 Bounce: function( p ) {
10627 while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
10628 return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
10632 $.each( baseEasings, function( name, easeIn ) {
10633 $.easing[ "easeIn" + name ] = easeIn;
10634 $.easing[ "easeOut" + name ] = function( p ) {
10635 return 1 - easeIn( 1 - p );
10637 $.easing[ "easeInOut" + name ] = function( p ) {
10639 easeIn( p * 2 ) / 2 :
10640 1 - easeIn( p * -2 + 2 ) / 2;
10646 var effect = $.effects;
10650 * jQuery UI Effects Blind 1.11.2
10651 * http://jqueryui.com
10653 * Copyright 2014 jQuery Foundation and other contributors
10654 * Released under the MIT license.
10655 * http://jquery.org/license
10657 * http://api.jqueryui.com/blind-effect/
10661 var effectBlind = $.effects.effect.blind = function( o, done ) {
10663 var el = $( this ),
10664 rvertical = /up|down|vertical/,
10665 rpositivemotion = /up|left|vertical|horizontal/,
10666 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
10667 mode = $.effects.setMode( el, o.mode || "hide" ),
10668 direction = o.direction || "up",
10669 vertical = rvertical.test( direction ),
10670 ref = vertical ? "height" : "width",
10671 ref2 = vertical ? "top" : "left",
10672 motion = rpositivemotion.test( direction ),
10674 show = mode === "show",
10675 wrapper, distance, margin;
10677 // if already wrapped, the wrapper's properties are my property. #6245
10678 if ( el.parent().is( ".ui-effects-wrapper" ) ) {
10679 $.effects.save( el.parent(), props );
10681 $.effects.save( el, props );
10684 wrapper = $.effects.createWrapper( el ).css({
10688 distance = wrapper[ ref ]();
10689 margin = parseFloat( wrapper.css( ref2 ) ) || 0;
10691 animation[ ref ] = show ? distance : 0;
10694 .css( vertical ? "bottom" : "right", 0 )
10695 .css( vertical ? "top" : "left", "auto" )
10696 .css({ position: "absolute" });
10698 animation[ ref2 ] = show ? margin : distance + margin;
10701 // start at 0 if we are showing
10703 wrapper.css( ref, 0 );
10705 wrapper.css( ref2, margin + distance );
10710 wrapper.animate( animation, {
10711 duration: o.duration,
10714 complete: function() {
10715 if ( mode === "hide" ) {
10718 $.effects.restore( el, props );
10719 $.effects.removeWrapper( el );
10727 * jQuery UI Effects Bounce 1.11.2
10728 * http://jqueryui.com
10730 * Copyright 2014 jQuery Foundation and other contributors
10731 * Released under the MIT license.
10732 * http://jquery.org/license
10734 * http://api.jqueryui.com/bounce-effect/
10738 var effectBounce = $.effects.effect.bounce = function( o, done ) {
10739 var el = $( this ),
10740 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
10743 mode = $.effects.setMode( el, o.mode || "effect" ),
10744 hide = mode === "hide",
10745 show = mode === "show",
10746 direction = o.direction || "up",
10747 distance = o.distance,
10748 times = o.times || 5,
10750 // number of internal animations
10751 anims = times * 2 + ( show || hide ? 1 : 0 ),
10752 speed = o.duration / anims,
10756 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
10757 motion = ( direction === "up" || direction === "left" ),
10762 // we will need to re-assemble the queue to stack our animations in place
10763 queue = el.queue(),
10764 queuelen = queue.length;
10766 // Avoid touching opacity to prevent clearType and PNG issues in IE
10767 if ( show || hide ) {
10768 props.push( "opacity" );
10771 $.effects.save( el, props );
10773 $.effects.createWrapper( el ); // Create Wrapper
10775 // default distance for the BIGGEST bounce is the outer Distance / 3
10777 distance = el[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
10781 downAnim = { opacity: 1 };
10782 downAnim[ ref ] = 0;
10784 // if we are showing, force opacity 0 and set the initial position
10785 // then do the "first" animation
10786 el.css( "opacity", 0 )
10787 .css( ref, motion ? -distance * 2 : distance * 2 )
10788 .animate( downAnim, speed, easing );
10791 // start at the smallest distance if we are hiding
10793 distance = distance / Math.pow( 2, times - 1 );
10797 downAnim[ ref ] = 0;
10798 // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
10799 for ( i = 0; i < times; i++ ) {
10801 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
10803 el.animate( upAnim, speed, easing )
10804 .animate( downAnim, speed, easing );
10806 distance = hide ? distance * 2 : distance / 2;
10809 // Last Bounce when Hiding
10811 upAnim = { opacity: 0 };
10812 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
10814 el.animate( upAnim, speed, easing );
10817 el.queue(function() {
10821 $.effects.restore( el, props );
10822 $.effects.removeWrapper( el );
10826 // inject all the animations we just queued to be first in line (after "inprogress")
10827 if ( queuelen > 1) {
10828 queue.splice.apply( queue,
10829 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
10837 * jQuery UI Effects Clip 1.11.2
10838 * http://jqueryui.com
10840 * Copyright 2014 jQuery Foundation and other contributors
10841 * Released under the MIT license.
10842 * http://jquery.org/license
10844 * http://api.jqueryui.com/clip-effect/
10848 var effectClip = $.effects.effect.clip = function( o, done ) {
10850 var el = $( this ),
10851 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
10852 mode = $.effects.setMode( el, o.mode || "hide" ),
10853 show = mode === "show",
10854 direction = o.direction || "vertical",
10855 vert = direction === "vertical",
10856 size = vert ? "height" : "width",
10857 position = vert ? "top" : "left",
10859 wrapper, animate, distance;
10862 $.effects.save( el, props );
10866 wrapper = $.effects.createWrapper( el ).css({
10869 animate = ( el[0].tagName === "IMG" ) ? wrapper : el;
10870 distance = animate[ size ]();
10874 animate.css( size, 0 );
10875 animate.css( position, distance / 2 );
10878 // Create Animation Object:
10879 animation[ size ] = show ? distance : 0;
10880 animation[ position ] = show ? 0 : distance / 2;
10883 animate.animate( animation, {
10885 duration: o.duration,
10887 complete: function() {
10891 $.effects.restore( el, props );
10892 $.effects.removeWrapper( el );
10901 * jQuery UI Effects Drop 1.11.2
10902 * http://jqueryui.com
10904 * Copyright 2014 jQuery Foundation and other contributors
10905 * Released under the MIT license.
10906 * http://jquery.org/license
10908 * http://api.jqueryui.com/drop-effect/
10912 var effectDrop = $.effects.effect.drop = function( o, done ) {
10914 var el = $( this ),
10915 props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ],
10916 mode = $.effects.setMode( el, o.mode || "hide" ),
10917 show = mode === "show",
10918 direction = o.direction || "left",
10919 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
10920 motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg",
10922 opacity: show ? 1 : 0
10927 $.effects.save( el, props );
10929 $.effects.createWrapper( el );
10931 distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ) / 2;
10935 .css( "opacity", 0 )
10936 .css( ref, motion === "pos" ? -distance : distance );
10940 animation[ ref ] = ( show ?
10941 ( motion === "pos" ? "+=" : "-=" ) :
10942 ( motion === "pos" ? "-=" : "+=" ) ) +
10946 el.animate( animation, {
10948 duration: o.duration,
10950 complete: function() {
10951 if ( mode === "hide" ) {
10954 $.effects.restore( el, props );
10955 $.effects.removeWrapper( el );
10963 * jQuery UI Effects Explode 1.11.2
10964 * http://jqueryui.com
10966 * Copyright 2014 jQuery Foundation and other contributors
10967 * Released under the MIT license.
10968 * http://jquery.org/license
10970 * http://api.jqueryui.com/explode-effect/
10974 var effectExplode = $.effects.effect.explode = function( o, done ) {
10976 var rows = o.pieces ? Math.round( Math.sqrt( o.pieces ) ) : 3,
10979 mode = $.effects.setMode( el, o.mode || "hide" ),
10980 show = mode === "show",
10982 // show and then visibility:hidden the element before calculating offset
10983 offset = el.show().css( "visibility", "hidden" ).offset(),
10985 // width and height of a piece
10986 width = Math.ceil( el.outerWidth() / cells ),
10987 height = Math.ceil( el.outerHeight() / rows ),
10991 i, j, left, top, mx, my;
10993 // children animate complete:
10994 function childComplete() {
10995 pieces.push( this );
10996 if ( pieces.length === rows * cells ) {
11001 // clone the element for each row and cell.
11002 for ( i = 0; i < rows ; i++ ) { // ===>
11003 top = offset.top + i * height;
11004 my = i - ( rows - 1 ) / 2 ;
11006 for ( j = 0; j < cells ; j++ ) { // |||
11007 left = offset.left + j * width;
11008 mx = j - ( cells - 1 ) / 2 ;
11010 // Create a clone of the now hidden main element that will be absolute positioned
11011 // within a wrapper div off the -left and -top equal to size of our pieces
11014 .appendTo( "body" )
11015 .wrap( "<div></div>" )
11017 position: "absolute",
11018 visibility: "visible",
11023 // select the wrapper - make it overflow: hidden and absolute positioned based on
11024 // where the original was located +left and +top equal to the size of pieces
11026 .addClass( "ui-effects-explode" )
11028 position: "absolute",
11029 overflow: "hidden",
11032 left: left + ( show ? mx * width : 0 ),
11033 top: top + ( show ? my * height : 0 ),
11034 opacity: show ? 0 : 1
11036 left: left + ( show ? 0 : mx * width ),
11037 top: top + ( show ? 0 : my * height ),
11038 opacity: show ? 1 : 0
11039 }, o.duration || 500, o.easing, childComplete );
11043 function animComplete() {
11045 visibility: "visible"
11047 $( pieces ).remove();
11057 * jQuery UI Effects Fade 1.11.2
11058 * http://jqueryui.com
11060 * Copyright 2014 jQuery Foundation and other contributors
11061 * Released under the MIT license.
11062 * http://jquery.org/license
11064 * http://api.jqueryui.com/fade-effect/
11068 var effectFade = $.effects.effect.fade = function( o, done ) {
11069 var el = $( this ),
11070 mode = $.effects.setMode( el, o.mode || "toggle" );
11076 duration: o.duration,
11084 * jQuery UI Effects Fold 1.11.2
11085 * http://jqueryui.com
11087 * Copyright 2014 jQuery Foundation and other contributors
11088 * Released under the MIT license.
11089 * http://jquery.org/license
11091 * http://api.jqueryui.com/fold-effect/
11095 var effectFold = $.effects.effect.fold = function( o, done ) {
11098 var el = $( this ),
11099 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
11100 mode = $.effects.setMode( el, o.mode || "hide" ),
11101 show = mode === "show",
11102 hide = mode === "hide",
11103 size = o.size || 15,
11104 percent = /([0-9]+)%/.exec( size ),
11105 horizFirst = !!o.horizFirst,
11106 widthFirst = show !== horizFirst,
11107 ref = widthFirst ? [ "width", "height" ] : [ "height", "width" ],
11108 duration = o.duration / 2,
11113 $.effects.save( el, props );
11117 wrapper = $.effects.createWrapper( el ).css({
11120 distance = widthFirst ?
11121 [ wrapper.width(), wrapper.height() ] :
11122 [ wrapper.height(), wrapper.width() ];
11125 size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
11128 wrapper.css( horizFirst ? {
11138 animation1[ ref[ 0 ] ] = show ? distance[ 0 ] : size;
11139 animation2[ ref[ 1 ] ] = show ? distance[ 1 ] : 0;
11143 .animate( animation1, duration, o.easing )
11144 .animate( animation2, duration, o.easing, function() {
11148 $.effects.restore( el, props );
11149 $.effects.removeWrapper( el );
11157 * jQuery UI Effects Highlight 1.11.2
11158 * http://jqueryui.com
11160 * Copyright 2014 jQuery Foundation and other contributors
11161 * Released under the MIT license.
11162 * http://jquery.org/license
11164 * http://api.jqueryui.com/highlight-effect/
11168 var effectHighlight = $.effects.effect.highlight = function( o, done ) {
11169 var elem = $( this ),
11170 props = [ "backgroundImage", "backgroundColor", "opacity" ],
11171 mode = $.effects.setMode( elem, o.mode || "show" ),
11173 backgroundColor: elem.css( "backgroundColor" )
11176 if (mode === "hide") {
11177 animation.opacity = 0;
11180 $.effects.save( elem, props );
11185 backgroundImage: "none",
11186 backgroundColor: o.color || "#ffff99"
11188 .animate( animation, {
11190 duration: o.duration,
11192 complete: function() {
11193 if ( mode === "hide" ) {
11196 $.effects.restore( elem, props );
11204 * jQuery UI Effects Size 1.11.2
11205 * http://jqueryui.com
11207 * Copyright 2014 jQuery Foundation and other contributors
11208 * Released under the MIT license.
11209 * http://jquery.org/license
11211 * http://api.jqueryui.com/size-effect/
11215 var effectSize = $.effects.effect.size = function( o, done ) {
11218 var original, baseline, factor,
11220 props0 = [ "position", "top", "bottom", "left", "right", "width", "height", "overflow", "opacity" ],
11223 props1 = [ "position", "top", "bottom", "left", "right", "overflow", "opacity" ],
11225 // Copy for children
11226 props2 = [ "width", "height", "overflow" ],
11227 cProps = [ "fontSize" ],
11228 vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
11229 hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],
11232 mode = $.effects.setMode( el, o.mode || "effect" ),
11233 restore = o.restore || mode !== "effect",
11234 scale = o.scale || "both",
11235 origin = o.origin || [ "middle", "center" ],
11236 position = el.css( "position" ),
11237 props = restore ? props0 : props1,
11245 if ( mode === "show" ) {
11249 height: el.height(),
11251 outerHeight: el.outerHeight(),
11252 outerWidth: el.outerWidth()
11255 if ( o.mode === "toggle" && mode === "show" ) {
11256 el.from = o.to || zero;
11257 el.to = o.from || original;
11259 el.from = o.from || ( mode === "show" ? zero : original );
11260 el.to = o.to || ( mode === "hide" ? zero : original );
11263 // Set scaling factor
11266 y: el.from.height / original.height,
11267 x: el.from.width / original.width
11270 y: el.to.height / original.height,
11271 x: el.to.width / original.width
11275 // Scale the css box
11276 if ( scale === "box" || scale === "both" ) {
11278 // Vertical props scaling
11279 if ( factor.from.y !== factor.to.y ) {
11280 props = props.concat( vProps );
11281 el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from );
11282 el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to );
11285 // Horizontal props scaling
11286 if ( factor.from.x !== factor.to.x ) {
11287 props = props.concat( hProps );
11288 el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from );
11289 el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to );
11293 // Scale the content
11294 if ( scale === "content" || scale === "both" ) {
11296 // Vertical props scaling
11297 if ( factor.from.y !== factor.to.y ) {
11298 props = props.concat( cProps ).concat( props2 );
11299 el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from );
11300 el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to );
11304 $.effects.save( el, props );
11306 $.effects.createWrapper( el );
11307 el.css( "overflow", "hidden" ).css( el.from );
11310 if (origin) { // Calculate baseline shifts
11311 baseline = $.effects.getBaseline( origin, original );
11312 el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y;
11313 el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x;
11314 el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y;
11315 el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x;
11317 el.css( el.from ); // set top & left
11320 if ( scale === "content" || scale === "both" ) { // Scale the children
11322 // Add margins/font-size
11323 vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat(cProps);
11324 hProps = hProps.concat([ "marginLeft", "marginRight" ]);
11325 props2 = props0.concat(vProps).concat(hProps);
11327 el.find( "*[width]" ).each( function() {
11328 var child = $( this ),
11330 height: child.height(),
11331 width: child.width(),
11332 outerHeight: child.outerHeight(),
11333 outerWidth: child.outerWidth()
11336 $.effects.save(child, props2);
11340 height: c_original.height * factor.from.y,
11341 width: c_original.width * factor.from.x,
11342 outerHeight: c_original.outerHeight * factor.from.y,
11343 outerWidth: c_original.outerWidth * factor.from.x
11346 height: c_original.height * factor.to.y,
11347 width: c_original.width * factor.to.x,
11348 outerHeight: c_original.height * factor.to.y,
11349 outerWidth: c_original.width * factor.to.x
11352 // Vertical props scaling
11353 if ( factor.from.y !== factor.to.y ) {
11354 child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from );
11355 child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to );
11358 // Horizontal props scaling
11359 if ( factor.from.x !== factor.to.x ) {
11360 child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from );
11361 child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to );
11364 // Animate children
11365 child.css( child.from );
11366 child.animate( child.to, o.duration, o.easing, function() {
11368 // Restore children
11370 $.effects.restore( child, props2 );
11377 el.animate( el.to, {
11379 duration: o.duration,
11381 complete: function() {
11382 if ( el.to.opacity === 0 ) {
11383 el.css( "opacity", el.from.opacity );
11385 if ( mode === "hide" ) {
11388 $.effects.restore( el, props );
11391 // we need to calculate our new positioning based on the scaling
11392 if ( position === "static" ) {
11394 position: "relative",
11399 $.each([ "top", "left" ], function( idx, pos ) {
11400 el.css( pos, function( _, str ) {
11401 var val = parseInt( str, 10 ),
11402 toRef = idx ? el.to.left : el.to.top;
11404 // if original was "auto", recalculate the new value from wrapper
11405 if ( str === "auto" ) {
11406 return toRef + "px";
11409 return val + toRef + "px";
11415 $.effects.removeWrapper( el );
11424 * jQuery UI Effects Scale 1.11.2
11425 * http://jqueryui.com
11427 * Copyright 2014 jQuery Foundation and other contributors
11428 * Released under the MIT license.
11429 * http://jquery.org/license
11431 * http://api.jqueryui.com/scale-effect/
11435 var effectScale = $.effects.effect.scale = function( o, done ) {
11438 var el = $( this ),
11439 options = $.extend( true, {}, o ),
11440 mode = $.effects.setMode( el, o.mode || "effect" ),
11441 percent = parseInt( o.percent, 10 ) ||
11442 ( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === "hide" ? 0 : 100 ) ),
11443 direction = o.direction || "both",
11446 height: el.height(),
11448 outerHeight: el.outerHeight(),
11449 outerWidth: el.outerWidth()
11452 y: direction !== "horizontal" ? (percent / 100) : 1,
11453 x: direction !== "vertical" ? (percent / 100) : 1
11456 // We are going to pass this effect to the size effect:
11457 options.effect = "size";
11458 options.queue = false;
11459 options.complete = done;
11461 // Set default origin and restore for show/hide
11462 if ( mode !== "effect" ) {
11463 options.origin = origin || [ "middle", "center" ];
11464 options.restore = true;
11467 options.from = o.from || ( mode === "show" ? {
11474 height: original.height * factor.y,
11475 width: original.width * factor.x,
11476 outerHeight: original.outerHeight * factor.y,
11477 outerWidth: original.outerWidth * factor.x
11480 // Fade option to support puff
11481 if ( options.fade ) {
11482 if ( mode === "show" ) {
11483 options.from.opacity = 0;
11484 options.to.opacity = 1;
11486 if ( mode === "hide" ) {
11487 options.from.opacity = 1;
11488 options.to.opacity = 0;
11493 el.effect( options );
11499 * jQuery UI Effects Puff 1.11.2
11500 * http://jqueryui.com
11502 * Copyright 2014 jQuery Foundation and other contributors
11503 * Released under the MIT license.
11504 * http://jquery.org/license
11506 * http://api.jqueryui.com/puff-effect/
11510 var effectPuff = $.effects.effect.puff = function( o, done ) {
11511 var elem = $( this ),
11512 mode = $.effects.setMode( elem, o.mode || "hide" ),
11513 hide = mode === "hide",
11514 percent = parseInt( o.percent, 10 ) || 150,
11515 factor = percent / 100,
11517 height: elem.height(),
11518 width: elem.width(),
11519 outerHeight: elem.outerHeight(),
11520 outerWidth: elem.outerWidth()
11529 percent: hide ? percent : 100,
11533 height: original.height * factor,
11534 width: original.width * factor,
11535 outerHeight: original.outerHeight * factor,
11536 outerWidth: original.outerWidth * factor
11545 * jQuery UI Effects Pulsate 1.11.2
11546 * http://jqueryui.com
11548 * Copyright 2014 jQuery Foundation and other contributors
11549 * Released under the MIT license.
11550 * http://jquery.org/license
11552 * http://api.jqueryui.com/pulsate-effect/
11556 var effectPulsate = $.effects.effect.pulsate = function( o, done ) {
11557 var elem = $( this ),
11558 mode = $.effects.setMode( elem, o.mode || "show" ),
11559 show = mode === "show",
11560 hide = mode === "hide",
11561 showhide = ( show || mode === "hide" ),
11563 // showing or hiding leaves of the "last" animation
11564 anims = ( ( o.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
11565 duration = o.duration / anims,
11567 queue = elem.queue(),
11568 queuelen = queue.length,
11571 if ( show || !elem.is(":visible")) {
11572 elem.css( "opacity", 0 ).show();
11576 // anims - 1 opacity "toggles"
11577 for ( i = 1; i < anims; i++ ) {
11580 }, duration, o.easing );
11581 animateTo = 1 - animateTo;
11586 }, duration, o.easing);
11588 elem.queue(function() {
11595 // We just queued up "anims" animations, we need to put them next in the queue
11596 if ( queuelen > 1 ) {
11597 queue.splice.apply( queue,
11598 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
11605 * jQuery UI Effects Shake 1.11.2
11606 * http://jqueryui.com
11608 * Copyright 2014 jQuery Foundation and other contributors
11609 * Released under the MIT license.
11610 * http://jquery.org/license
11612 * http://api.jqueryui.com/shake-effect/
11616 var effectShake = $.effects.effect.shake = function( o, done ) {
11618 var el = $( this ),
11619 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
11620 mode = $.effects.setMode( el, o.mode || "effect" ),
11621 direction = o.direction || "left",
11622 distance = o.distance || 20,
11623 times = o.times || 3,
11624 anims = times * 2 + 1,
11625 speed = Math.round( o.duration / anims ),
11626 ref = (direction === "up" || direction === "down") ? "top" : "left",
11627 positiveMotion = (direction === "up" || direction === "left"),
11633 // we will need to re-assemble the queue to stack our animations in place
11634 queue = el.queue(),
11635 queuelen = queue.length;
11637 $.effects.save( el, props );
11639 $.effects.createWrapper( el );
11642 animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
11643 animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
11644 animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;
11647 el.animate( animation, speed, o.easing );
11650 for ( i = 1; i < times; i++ ) {
11651 el.animate( animation1, speed, o.easing ).animate( animation2, speed, o.easing );
11654 .animate( animation1, speed, o.easing )
11655 .animate( animation, speed / 2, o.easing )
11656 .queue(function() {
11657 if ( mode === "hide" ) {
11660 $.effects.restore( el, props );
11661 $.effects.removeWrapper( el );
11665 // inject all the animations we just queued to be first in line (after "inprogress")
11666 if ( queuelen > 1) {
11667 queue.splice.apply( queue,
11668 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
11676 * jQuery UI Effects Slide 1.11.2
11677 * http://jqueryui.com
11679 * Copyright 2014 jQuery Foundation and other contributors
11680 * Released under the MIT license.
11681 * http://jquery.org/license
11683 * http://api.jqueryui.com/slide-effect/
11687 var effectSlide = $.effects.effect.slide = function( o, done ) {
11690 var el = $( this ),
11691 props = [ "position", "top", "bottom", "left", "right", "width", "height" ],
11692 mode = $.effects.setMode( el, o.mode || "show" ),
11693 show = mode === "show",
11694 direction = o.direction || "left",
11695 ref = (direction === "up" || direction === "down") ? "top" : "left",
11696 positiveMotion = (direction === "up" || direction === "left"),
11701 $.effects.save( el, props );
11703 distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true );
11705 $.effects.createWrapper( el ).css({
11710 el.css( ref, positiveMotion ? (isNaN(distance) ? "-" + distance : -distance) : distance );
11714 animation[ ref ] = ( show ?
11715 ( positiveMotion ? "+=" : "-=") :
11716 ( positiveMotion ? "-=" : "+=")) +
11720 el.animate( animation, {
11722 duration: o.duration,
11724 complete: function() {
11725 if ( mode === "hide" ) {
11728 $.effects.restore( el, props );
11729 $.effects.removeWrapper( el );
11737 * jQuery UI Effects Transfer 1.11.2
11738 * http://jqueryui.com
11740 * Copyright 2014 jQuery Foundation and other contributors
11741 * Released under the MIT license.
11742 * http://jquery.org/license
11744 * http://api.jqueryui.com/transfer-effect/
11748 var effectTransfer = $.effects.effect.transfer = function( o, done ) {
11749 var elem = $( this ),
11750 target = $( o.to ),
11751 targetFixed = target.css( "position" ) === "fixed",
11753 fixTop = targetFixed ? body.scrollTop() : 0,
11754 fixLeft = targetFixed ? body.scrollLeft() : 0,
11755 endPosition = target.offset(),
11757 top: endPosition.top - fixTop,
11758 left: endPosition.left - fixLeft,
11759 height: target.innerHeight(),
11760 width: target.innerWidth()
11762 startPosition = elem.offset(),
11763 transfer = $( "<div class='ui-effects-transfer'></div>" )
11764 .appendTo( document.body )
11765 .addClass( o.className )
11767 top: startPosition.top - fixTop,
11768 left: startPosition.left - fixLeft,
11769 height: elem.innerHeight(),
11770 width: elem.innerWidth(),
11771 position: targetFixed ? "fixed" : "absolute"
11773 .animate( animation, o.duration, o.easing, function() {
11781 * jQuery UI Progressbar 1.11.2
11782 * http://jqueryui.com
11784 * Copyright 2014 jQuery Foundation and other contributors
11785 * Released under the MIT license.
11786 * http://jquery.org/license
11788 * http://api.jqueryui.com/progressbar/
11792 var progressbar = $.widget( "ui.progressbar", {
11804 _create: function() {
11805 // Constrain initial value
11806 this.oldValue = this.options.value = this._constrainedValue();
11809 .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
11811 // Only set static values, aria-valuenow and aria-valuemax are
11812 // set inside _refreshValue()
11813 role: "progressbar",
11814 "aria-valuemin": this.min
11817 this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" )
11818 .appendTo( this.element );
11820 this._refreshValue();
11823 _destroy: function() {
11825 .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
11826 .removeAttr( "role" )
11827 .removeAttr( "aria-valuemin" )
11828 .removeAttr( "aria-valuemax" )
11829 .removeAttr( "aria-valuenow" );
11831 this.valueDiv.remove();
11834 value: function( newValue ) {
11835 if ( newValue === undefined ) {
11836 return this.options.value;
11839 this.options.value = this._constrainedValue( newValue );
11840 this._refreshValue();
11843 _constrainedValue: function( newValue ) {
11844 if ( newValue === undefined ) {
11845 newValue = this.options.value;
11848 this.indeterminate = newValue === false;
11851 if ( typeof newValue !== "number" ) {
11855 return this.indeterminate ? false :
11856 Math.min( this.options.max, Math.max( this.min, newValue ) );
11859 _setOptions: function( options ) {
11860 // Ensure "value" option is set after other values (like max)
11861 var value = options.value;
11862 delete options.value;
11864 this._super( options );
11866 this.options.value = this._constrainedValue( value );
11867 this._refreshValue();
11870 _setOption: function( key, value ) {
11871 if ( key === "max" ) {
11872 // Don't allow a max less than min
11873 value = Math.max( this.min, value );
11875 if ( key === "disabled" ) {
11877 .toggleClass( "ui-state-disabled", !!value )
11878 .attr( "aria-disabled", value );
11880 this._super( key, value );
11883 _percentage: function() {
11884 return this.indeterminate ? 100 : 100 * ( this.options.value - this.min ) / ( this.options.max - this.min );
11887 _refreshValue: function() {
11888 var value = this.options.value,
11889 percentage = this._percentage();
11892 .toggle( this.indeterminate || value > this.min )
11893 .toggleClass( "ui-corner-right", value === this.options.max )
11894 .width( percentage.toFixed(0) + "%" );
11896 this.element.toggleClass( "ui-progressbar-indeterminate", this.indeterminate );
11898 if ( this.indeterminate ) {
11899 this.element.removeAttr( "aria-valuenow" );
11900 if ( !this.overlayDiv ) {
11901 this.overlayDiv = $( "<div class='ui-progressbar-overlay'></div>" ).appendTo( this.valueDiv );
11904 this.element.attr({
11905 "aria-valuemax": this.options.max,
11906 "aria-valuenow": value
11908 if ( this.overlayDiv ) {
11909 this.overlayDiv.remove();
11910 this.overlayDiv = null;
11914 if ( this.oldValue !== value ) {
11915 this.oldValue = value;
11916 this._trigger( "change" );
11918 if ( value === this.options.max ) {
11919 this._trigger( "complete" );
11926 * jQuery UI Selectable 1.11.2
11927 * http://jqueryui.com
11929 * Copyright 2014 jQuery Foundation and other contributors
11930 * Released under the MIT license.
11931 * http://jquery.org/license
11933 * http://api.jqueryui.com/selectable/
11937 var selectable = $.widget("ui.selectable", $.ui.mouse, {
11944 tolerance: "touch",
11954 _create: function() {
11958 this.element.addClass("ui-selectable");
11960 this.dragged = false;
11962 // cache selectee children based on filter
11963 this.refresh = function() {
11964 selectees = $(that.options.filter, that.element[0]);
11965 selectees.addClass("ui-selectee");
11966 selectees.each(function() {
11967 var $this = $(this),
11968 pos = $this.offset();
11969 $.data(this, "selectable-item", {
11974 right: pos.left + $this.outerWidth(),
11975 bottom: pos.top + $this.outerHeight(),
11976 startselected: false,
11977 selected: $this.hasClass("ui-selected"),
11978 selecting: $this.hasClass("ui-selecting"),
11979 unselecting: $this.hasClass("ui-unselecting")
11985 this.selectees = selectees.addClass("ui-selectee");
11989 this.helper = $("<div class='ui-selectable-helper'></div>");
11992 _destroy: function() {
11994 .removeClass("ui-selectee")
11995 .removeData("selectable-item");
11997 .removeClass("ui-selectable ui-selectable-disabled");
11998 this._mouseDestroy();
12001 _mouseStart: function(event) {
12003 options = this.options;
12005 this.opos = [ event.pageX, event.pageY ];
12007 if (this.options.disabled) {
12011 this.selectees = $(options.filter, this.element[0]);
12013 this._trigger("start", event);
12015 $(options.appendTo).append(this.helper);
12016 // position helper (lasso)
12018 "left": event.pageX,
12019 "top": event.pageY,
12024 if (options.autoRefresh) {
12028 this.selectees.filter(".ui-selected").each(function() {
12029 var selectee = $.data(this, "selectable-item");
12030 selectee.startselected = true;
12031 if (!event.metaKey && !event.ctrlKey) {
12032 selectee.$element.removeClass("ui-selected");
12033 selectee.selected = false;
12034 selectee.$element.addClass("ui-unselecting");
12035 selectee.unselecting = true;
12036 // selectable UNSELECTING callback
12037 that._trigger("unselecting", event, {
12038 unselecting: selectee.element
12043 $(event.target).parents().addBack().each(function() {
12045 selectee = $.data(this, "selectable-item");
12047 doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass("ui-selected");
12049 .removeClass(doSelect ? "ui-unselecting" : "ui-selected")
12050 .addClass(doSelect ? "ui-selecting" : "ui-unselecting");
12051 selectee.unselecting = !doSelect;
12052 selectee.selecting = doSelect;
12053 selectee.selected = doSelect;
12054 // selectable (UN)SELECTING callback
12056 that._trigger("selecting", event, {
12057 selecting: selectee.element
12060 that._trigger("unselecting", event, {
12061 unselecting: selectee.element
12070 _mouseDrag: function(event) {
12072 this.dragged = true;
12074 if (this.options.disabled) {
12080 options = this.options,
12086 if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; }
12087 if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; }
12088 this.helper.css({ left: x1, top: y1, width: x2 - x1, height: y2 - y1 });
12090 this.selectees.each(function() {
12091 var selectee = $.data(this, "selectable-item"),
12094 //prevent helper from being selected if appendTo: selectable
12095 if (!selectee || selectee.element === that.element[0]) {
12099 if (options.tolerance === "touch") {
12100 hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) );
12101 } else if (options.tolerance === "fit") {
12102 hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2);
12107 if (selectee.selected) {
12108 selectee.$element.removeClass("ui-selected");
12109 selectee.selected = false;
12111 if (selectee.unselecting) {
12112 selectee.$element.removeClass("ui-unselecting");
12113 selectee.unselecting = false;
12115 if (!selectee.selecting) {
12116 selectee.$element.addClass("ui-selecting");
12117 selectee.selecting = true;
12118 // selectable SELECTING callback
12119 that._trigger("selecting", event, {
12120 selecting: selectee.element
12125 if (selectee.selecting) {
12126 if ((event.metaKey || event.ctrlKey) && selectee.startselected) {
12127 selectee.$element.removeClass("ui-selecting");
12128 selectee.selecting = false;
12129 selectee.$element.addClass("ui-selected");
12130 selectee.selected = true;
12132 selectee.$element.removeClass("ui-selecting");
12133 selectee.selecting = false;
12134 if (selectee.startselected) {
12135 selectee.$element.addClass("ui-unselecting");
12136 selectee.unselecting = true;
12138 // selectable UNSELECTING callback
12139 that._trigger("unselecting", event, {
12140 unselecting: selectee.element
12144 if (selectee.selected) {
12145 if (!event.metaKey && !event.ctrlKey && !selectee.startselected) {
12146 selectee.$element.removeClass("ui-selected");
12147 selectee.selected = false;
12149 selectee.$element.addClass("ui-unselecting");
12150 selectee.unselecting = true;
12151 // selectable UNSELECTING callback
12152 that._trigger("unselecting", event, {
12153 unselecting: selectee.element
12163 _mouseStop: function(event) {
12166 this.dragged = false;
12168 $(".ui-unselecting", this.element[0]).each(function() {
12169 var selectee = $.data(this, "selectable-item");
12170 selectee.$element.removeClass("ui-unselecting");
12171 selectee.unselecting = false;
12172 selectee.startselected = false;
12173 that._trigger("unselected", event, {
12174 unselected: selectee.element
12177 $(".ui-selecting", this.element[0]).each(function() {
12178 var selectee = $.data(this, "selectable-item");
12179 selectee.$element.removeClass("ui-selecting").addClass("ui-selected");
12180 selectee.selecting = false;
12181 selectee.selected = true;
12182 selectee.startselected = true;
12183 that._trigger("selected", event, {
12184 selected: selectee.element
12187 this._trigger("stop", event);
12189 this.helper.remove();
12198 * jQuery UI Selectmenu 1.11.2
12199 * http://jqueryui.com
12201 * Copyright 2014 jQuery Foundation and other contributors
12202 * Released under the MIT license.
12203 * http://jquery.org/license
12205 * http://api.jqueryui.com/selectmenu
12209 var selectmenu = $.widget( "ui.selectmenu", {
12211 defaultElement: "<select>",
12216 button: "ui-icon-triangle-1-s"
12233 _create: function() {
12234 var selectmenuId = this.element.uniqueId().attr( "id" );
12236 element: selectmenuId,
12237 button: selectmenuId + "-button",
12238 menu: selectmenuId + "-menu"
12241 this._drawButton();
12244 if ( this.options.disabled ) {
12249 _drawButton: function() {
12251 tabindex = this.element.attr( "tabindex" );
12253 // Associate existing label with the new button
12254 this.label = $( "label[for='" + this.ids.element + "']" ).attr( "for", this.ids.button );
12255 this._on( this.label, {
12256 click: function( event ) {
12257 this.button.focus();
12258 event.preventDefault();
12262 // Hide original select element
12263 this.element.hide();
12266 this.button = $( "<span>", {
12267 "class": "ui-selectmenu-button ui-widget ui-state-default ui-corner-all",
12268 tabindex: tabindex || this.options.disabled ? -1 : 0,
12269 id: this.ids.button,
12271 "aria-expanded": "false",
12272 "aria-autocomplete": "list",
12273 "aria-owns": this.ids.menu,
12274 "aria-haspopup": "true"
12276 .insertAfter( this.element );
12279 "class": "ui-icon " + this.options.icons.button
12281 .prependTo( this.button );
12283 this.buttonText = $( "<span>", {
12284 "class": "ui-selectmenu-text"
12286 .appendTo( this.button );
12288 this._setText( this.buttonText, this.element.find( "option:selected" ).text() );
12289 this._resizeButton();
12291 this._on( this.button, this._buttonEvents );
12292 this.button.one( "focusin", function() {
12294 // Delay rendering the menu items until the button receives focus.
12295 // The menu may have already been rendered via a programmatic open.
12296 if ( !that.menuItems ) {
12297 that._refreshMenu();
12300 this._hoverable( this.button );
12301 this._focusable( this.button );
12304 _drawMenu: function() {
12308 this.menu = $( "<ul>", {
12309 "aria-hidden": "true",
12310 "aria-labelledby": this.ids.button,
12315 this.menuWrap = $( "<div>", {
12316 "class": "ui-selectmenu-menu ui-front"
12318 .append( this.menu )
12319 .appendTo( this._appendTo() );
12321 // Initialize menu widget
12322 this.menuInstance = this.menu
12325 select: function( event, ui ) {
12326 event.preventDefault();
12329 // If the item was selected via a click, the text selection
12330 // will be destroyed in IE
12331 that._setSelection();
12333 that._select( ui.item.data( "ui-selectmenu-item" ), event );
12335 focus: function( event, ui ) {
12336 var item = ui.item.data( "ui-selectmenu-item" );
12338 // Prevent inital focus from firing and check if its a newly focused item
12339 if ( that.focusIndex != null && item.index !== that.focusIndex ) {
12340 that._trigger( "focus", event, { item: item } );
12341 if ( !that.isOpen ) {
12342 that._select( item, event );
12345 that.focusIndex = item.index;
12347 that.button.attr( "aria-activedescendant",
12348 that.menuItems.eq( item.index ).attr( "id" ) );
12351 .menu( "instance" );
12353 // Adjust menu styles to dropdown
12355 .addClass( "ui-corner-bottom" )
12356 .removeClass( "ui-corner-all" );
12358 // Don't close the menu on mouseleave
12359 this.menuInstance._off( this.menu, "mouseleave" );
12361 // Cancel the menu's collapseAll on document click
12362 this.menuInstance._closeOnDocumentClick = function() {
12366 // Selects often contain empty items, but never contain dividers
12367 this.menuInstance._isDivider = function() {
12372 refresh: function() {
12373 this._refreshMenu();
12374 this._setText( this.buttonText, this._getSelectedItem().text() );
12375 if ( !this.options.width ) {
12376 this._resizeButton();
12380 _refreshMenu: function() {
12384 options = this.element.find( "option" );
12386 if ( !options.length ) {
12390 this._parseOptions( options );
12391 this._renderMenu( this.menu, this.items );
12393 this.menuInstance.refresh();
12394 this.menuItems = this.menu.find( "li" ).not( ".ui-selectmenu-optgroup" );
12396 item = this._getSelectedItem();
12398 // Update the menu to have the correct item focused
12399 this.menuInstance.focus( null, item );
12400 this._setAria( item.data( "ui-selectmenu-item" ) );
12402 // Set disabled state
12403 this._setOption( "disabled", this.element.prop( "disabled" ) );
12406 open: function( event ) {
12407 if ( this.options.disabled ) {
12411 // If this is the first time the menu is being opened, render the items
12412 if ( !this.menuItems ) {
12413 this._refreshMenu();
12416 // Menu clears focus on close, reset focus to selected item
12417 this.menu.find( ".ui-state-focus" ).removeClass( "ui-state-focus" );
12418 this.menuInstance.focus( null, this._getSelectedItem() );
12421 this.isOpen = true;
12422 this._toggleAttr();
12423 this._resizeMenu();
12426 this._on( this.document, this._documentClick );
12428 this._trigger( "open", event );
12431 _position: function() {
12432 this.menuWrap.position( $.extend( { of: this.button }, this.options.position ) );
12435 close: function( event ) {
12436 if ( !this.isOpen ) {
12440 this.isOpen = false;
12441 this._toggleAttr();
12444 this._off( this.document );
12446 this._trigger( "close", event );
12449 widget: function() {
12450 return this.button;
12453 menuWidget: function() {
12457 _renderMenu: function( ul, items ) {
12459 currentOptgroup = "";
12461 $.each( items, function( index, item ) {
12462 if ( item.optgroup !== currentOptgroup ) {
12464 "class": "ui-selectmenu-optgroup ui-menu-divider" +
12465 ( item.element.parent( "optgroup" ).prop( "disabled" ) ?
12466 " ui-state-disabled" :
12468 text: item.optgroup
12472 currentOptgroup = item.optgroup;
12475 that._renderItemData( ul, item );
12479 _renderItemData: function( ul, item ) {
12480 return this._renderItem( ul, item ).data( "ui-selectmenu-item", item );
12483 _renderItem: function( ul, item ) {
12484 var li = $( "<li>" );
12486 if ( item.disabled ) {
12487 li.addClass( "ui-state-disabled" );
12489 this._setText( li, item.label );
12491 return li.appendTo( ul );
12494 _setText: function( element, value ) {
12496 element.text( value );
12498 element.html( " " );
12502 _move: function( direction, event ) {
12504 filter = ".ui-menu-item";
12506 if ( this.isOpen ) {
12507 item = this.menuItems.eq( this.focusIndex );
12509 item = this.menuItems.eq( this.element[ 0 ].selectedIndex );
12510 filter += ":not(.ui-state-disabled)";
12513 if ( direction === "first" || direction === "last" ) {
12514 next = item[ direction === "first" ? "prevAll" : "nextAll" ]( filter ).eq( -1 );
12516 next = item[ direction + "All" ]( filter ).eq( 0 );
12519 if ( next.length ) {
12520 this.menuInstance.focus( event, next );
12524 _getSelectedItem: function() {
12525 return this.menuItems.eq( this.element[ 0 ].selectedIndex );
12528 _toggle: function( event ) {
12529 this[ this.isOpen ? "close" : "open" ]( event );
12532 _setSelection: function() {
12535 if ( !this.range ) {
12539 if ( window.getSelection ) {
12540 selection = window.getSelection();
12541 selection.removeAllRanges();
12542 selection.addRange( this.range );
12546 this.range.select();
12550 // Setting the text selection kills the button focus in IE, but
12551 // restoring the focus doesn't kill the selection.
12552 this.button.focus();
12556 mousedown: function( event ) {
12557 if ( !this.isOpen ) {
12561 if ( !$( event.target ).closest( ".ui-selectmenu-menu, #" + this.ids.button ).length ) {
12562 this.close( event );
12569 // Prevent text selection from being reset when interacting with the selectmenu (#10144)
12570 mousedown: function() {
12573 if ( window.getSelection ) {
12574 selection = window.getSelection();
12575 if ( selection.rangeCount ) {
12576 this.range = selection.getRangeAt( 0 );
12581 this.range = document.selection.createRange();
12585 click: function( event ) {
12586 this._setSelection();
12587 this._toggle( event );
12590 keydown: function( event ) {
12591 var preventDefault = true;
12592 switch ( event.keyCode ) {
12593 case $.ui.keyCode.TAB:
12594 case $.ui.keyCode.ESCAPE:
12595 this.close( event );
12596 preventDefault = false;
12598 case $.ui.keyCode.ENTER:
12599 if ( this.isOpen ) {
12600 this._selectFocusedItem( event );
12603 case $.ui.keyCode.UP:
12604 if ( event.altKey ) {
12605 this._toggle( event );
12607 this._move( "prev", event );
12610 case $.ui.keyCode.DOWN:
12611 if ( event.altKey ) {
12612 this._toggle( event );
12614 this._move( "next", event );
12617 case $.ui.keyCode.SPACE:
12618 if ( this.isOpen ) {
12619 this._selectFocusedItem( event );
12621 this._toggle( event );
12624 case $.ui.keyCode.LEFT:
12625 this._move( "prev", event );
12627 case $.ui.keyCode.RIGHT:
12628 this._move( "next", event );
12630 case $.ui.keyCode.HOME:
12631 case $.ui.keyCode.PAGE_UP:
12632 this._move( "first", event );
12634 case $.ui.keyCode.END:
12635 case $.ui.keyCode.PAGE_DOWN:
12636 this._move( "last", event );
12639 this.menu.trigger( event );
12640 preventDefault = false;
12643 if ( preventDefault ) {
12644 event.preventDefault();
12649 _selectFocusedItem: function( event ) {
12650 var item = this.menuItems.eq( this.focusIndex );
12651 if ( !item.hasClass( "ui-state-disabled" ) ) {
12652 this._select( item.data( "ui-selectmenu-item" ), event );
12656 _select: function( item, event ) {
12657 var oldIndex = this.element[ 0 ].selectedIndex;
12659 // Change native select element
12660 this.element[ 0 ].selectedIndex = item.index;
12661 this._setText( this.buttonText, item.label );
12662 this._setAria( item );
12663 this._trigger( "select", event, { item: item } );
12665 if ( item.index !== oldIndex ) {
12666 this._trigger( "change", event, { item: item } );
12669 this.close( event );
12672 _setAria: function( item ) {
12673 var id = this.menuItems.eq( item.index ).attr( "id" );
12676 "aria-labelledby": id,
12677 "aria-activedescendant": id
12679 this.menu.attr( "aria-activedescendant", id );
12682 _setOption: function( key, value ) {
12683 if ( key === "icons" ) {
12684 this.button.find( "span.ui-icon" )
12685 .removeClass( this.options.icons.button )
12686 .addClass( value.button );
12689 this._super( key, value );
12691 if ( key === "appendTo" ) {
12692 this.menuWrap.appendTo( this._appendTo() );
12695 if ( key === "disabled" ) {
12696 this.menuInstance.option( "disabled", value );
12698 .toggleClass( "ui-state-disabled", value )
12699 .attr( "aria-disabled", value );
12701 this.element.prop( "disabled", value );
12703 this.button.attr( "tabindex", -1 );
12706 this.button.attr( "tabindex", 0 );
12710 if ( key === "width" ) {
12711 this._resizeButton();
12715 _appendTo: function() {
12716 var element = this.options.appendTo;
12719 element = element.jquery || element.nodeType ?
12721 this.document.find( element ).eq( 0 );
12724 if ( !element || !element[ 0 ] ) {
12725 element = this.element.closest( ".ui-front" );
12728 if ( !element.length ) {
12729 element = this.document[ 0 ].body;
12735 _toggleAttr: function() {
12737 .toggleClass( "ui-corner-top", this.isOpen )
12738 .toggleClass( "ui-corner-all", !this.isOpen )
12739 .attr( "aria-expanded", this.isOpen );
12740 this.menuWrap.toggleClass( "ui-selectmenu-open", this.isOpen );
12741 this.menu.attr( "aria-hidden", !this.isOpen );
12744 _resizeButton: function() {
12745 var width = this.options.width;
12748 width = this.element.show().outerWidth();
12749 this.element.hide();
12752 this.button.outerWidth( width );
12755 _resizeMenu: function() {
12756 this.menu.outerWidth( Math.max(
12757 this.button.outerWidth(),
12760 // IE10 wraps long text (possibly a rounding bug)
12761 // so we add 1px to avoid the wrapping
12762 this.menu.width( "" ).outerWidth() + 1
12766 _getCreateOptions: function() {
12767 return { disabled: this.element.prop( "disabled" ) };
12770 _parseOptions: function( options ) {
12772 options.each(function( index, item ) {
12773 var option = $( item ),
12774 optgroup = option.parent( "optgroup" );
12778 value: option.attr( "value" ),
12779 label: option.text(),
12780 optgroup: optgroup.attr( "label" ) || "",
12781 disabled: optgroup.prop( "disabled" ) || option.prop( "disabled" )
12787 _destroy: function() {
12788 this.menuWrap.remove();
12789 this.button.remove();
12790 this.element.show();
12791 this.element.removeUniqueId();
12792 this.label.attr( "for", this.ids.element );
12798 * jQuery UI Slider 1.11.2
12799 * http://jqueryui.com
12801 * Copyright 2014 jQuery Foundation and other contributors
12802 * Released under the MIT license.
12803 * http://jquery.org/license
12805 * http://api.jqueryui.com/slider/
12809 var slider = $.widget( "ui.slider", $.ui.mouse, {
12811 widgetEventPrefix: "slide",
12818 orientation: "horizontal",
12831 // number of pages in a slider
12832 // (how many times can you page up/down to go through the whole range)
12835 _create: function() {
12836 this._keySliding = false;
12837 this._mouseSliding = false;
12838 this._animateOff = true;
12839 this._handleIndex = null;
12840 this._detectOrientation();
12842 this._calculateNewMax();
12845 .addClass( "ui-slider" +
12846 " ui-slider-" + this.orientation +
12848 " ui-widget-content" +
12852 this._setOption( "disabled", this.options.disabled );
12854 this._animateOff = false;
12857 _refresh: function() {
12858 this._createRange();
12859 this._createHandles();
12860 this._setupEvents();
12861 this._refreshValue();
12864 _createHandles: function() {
12865 var i, handleCount,
12866 options = this.options,
12867 existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ),
12868 handle = "<span class='ui-slider-handle ui-state-default ui-corner-all' tabindex='0'></span>",
12871 handleCount = ( options.values && options.values.length ) || 1;
12873 if ( existingHandles.length > handleCount ) {
12874 existingHandles.slice( handleCount ).remove();
12875 existingHandles = existingHandles.slice( 0, handleCount );
12878 for ( i = existingHandles.length; i < handleCount; i++ ) {
12879 handles.push( handle );
12882 this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
12884 this.handle = this.handles.eq( 0 );
12886 this.handles.each(function( i ) {
12887 $( this ).data( "ui-slider-handle-index", i );
12891 _createRange: function() {
12892 var options = this.options,
12895 if ( options.range ) {
12896 if ( options.range === true ) {
12897 if ( !options.values ) {
12898 options.values = [ this._valueMin(), this._valueMin() ];
12899 } else if ( options.values.length && options.values.length !== 2 ) {
12900 options.values = [ options.values[0], options.values[0] ];
12901 } else if ( $.isArray( options.values ) ) {
12902 options.values = options.values.slice(0);
12906 if ( !this.range || !this.range.length ) {
12907 this.range = $( "<div></div>" )
12908 .appendTo( this.element );
12910 classes = "ui-slider-range" +
12911 // note: this isn't the most fittingly semantic framework class for this element,
12912 // but worked best visually with a variety of themes
12913 " ui-widget-header ui-corner-all";
12915 this.range.removeClass( "ui-slider-range-min ui-slider-range-max" )
12916 // Handle range switching from true to min/max
12923 this.range.addClass( classes +
12924 ( ( options.range === "min" || options.range === "max" ) ? " ui-slider-range-" + options.range : "" ) );
12926 if ( this.range ) {
12927 this.range.remove();
12933 _setupEvents: function() {
12934 this._off( this.handles );
12935 this._on( this.handles, this._handleEvents );
12936 this._hoverable( this.handles );
12937 this._focusable( this.handles );
12940 _destroy: function() {
12941 this.handles.remove();
12942 if ( this.range ) {
12943 this.range.remove();
12947 .removeClass( "ui-slider" +
12948 " ui-slider-horizontal" +
12949 " ui-slider-vertical" +
12951 " ui-widget-content" +
12952 " ui-corner-all" );
12954 this._mouseDestroy();
12957 _mouseCapture: function( event ) {
12958 var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
12962 if ( o.disabled ) {
12966 this.elementSize = {
12967 width: this.element.outerWidth(),
12968 height: this.element.outerHeight()
12970 this.elementOffset = this.element.offset();
12972 position = { x: event.pageX, y: event.pageY };
12973 normValue = this._normValueFromMouse( position );
12974 distance = this._valueMax() - this._valueMin() + 1;
12975 this.handles.each(function( i ) {
12976 var thisDistance = Math.abs( normValue - that.values(i) );
12977 if (( distance > thisDistance ) ||
12978 ( distance === thisDistance &&
12979 (i === that._lastChangedValue || that.values(i) === o.min ))) {
12980 distance = thisDistance;
12981 closestHandle = $( this );
12986 allowed = this._start( event, index );
12987 if ( allowed === false ) {
12990 this._mouseSliding = true;
12992 this._handleIndex = index;
12995 .addClass( "ui-state-active" )
12998 offset = closestHandle.offset();
12999 mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
13000 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
13001 left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
13002 top: event.pageY - offset.top -
13003 ( closestHandle.height() / 2 ) -
13004 ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) -
13005 ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) +
13006 ( parseInt( closestHandle.css("marginTop"), 10 ) || 0)
13009 if ( !this.handles.hasClass( "ui-state-hover" ) ) {
13010 this._slide( event, index, normValue );
13012 this._animateOff = true;
13016 _mouseStart: function() {
13020 _mouseDrag: function( event ) {
13021 var position = { x: event.pageX, y: event.pageY },
13022 normValue = this._normValueFromMouse( position );
13024 this._slide( event, this._handleIndex, normValue );
13029 _mouseStop: function( event ) {
13030 this.handles.removeClass( "ui-state-active" );
13031 this._mouseSliding = false;
13033 this._stop( event, this._handleIndex );
13034 this._change( event, this._handleIndex );
13036 this._handleIndex = null;
13037 this._clickOffset = null;
13038 this._animateOff = false;
13043 _detectOrientation: function() {
13044 this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
13047 _normValueFromMouse: function( position ) {
13054 if ( this.orientation === "horizontal" ) {
13055 pixelTotal = this.elementSize.width;
13056 pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
13058 pixelTotal = this.elementSize.height;
13059 pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );
13062 percentMouse = ( pixelMouse / pixelTotal );
13063 if ( percentMouse > 1 ) {
13066 if ( percentMouse < 0 ) {
13069 if ( this.orientation === "vertical" ) {
13070 percentMouse = 1 - percentMouse;
13073 valueTotal = this._valueMax() - this._valueMin();
13074 valueMouse = this._valueMin() + percentMouse * valueTotal;
13076 return this._trimAlignValue( valueMouse );
13079 _start: function( event, index ) {
13081 handle: this.handles[ index ],
13082 value: this.value()
13084 if ( this.options.values && this.options.values.length ) {
13085 uiHash.value = this.values( index );
13086 uiHash.values = this.values();
13088 return this._trigger( "start", event, uiHash );
13091 _slide: function( event, index, newVal ) {
13096 if ( this.options.values && this.options.values.length ) {
13097 otherVal = this.values( index ? 0 : 1 );
13099 if ( ( this.options.values.length === 2 && this.options.range === true ) &&
13100 ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )
13105 if ( newVal !== this.values( index ) ) {
13106 newValues = this.values();
13107 newValues[ index ] = newVal;
13108 // A slide can be canceled by returning false from the slide callback
13109 allowed = this._trigger( "slide", event, {
13110 handle: this.handles[ index ],
13114 otherVal = this.values( index ? 0 : 1 );
13115 if ( allowed !== false ) {
13116 this.values( index, newVal );
13120 if ( newVal !== this.value() ) {
13121 // A slide can be canceled by returning false from the slide callback
13122 allowed = this._trigger( "slide", event, {
13123 handle: this.handles[ index ],
13126 if ( allowed !== false ) {
13127 this.value( newVal );
13133 _stop: function( event, index ) {
13135 handle: this.handles[ index ],
13136 value: this.value()
13138 if ( this.options.values && this.options.values.length ) {
13139 uiHash.value = this.values( index );
13140 uiHash.values = this.values();
13143 this._trigger( "stop", event, uiHash );
13146 _change: function( event, index ) {
13147 if ( !this._keySliding && !this._mouseSliding ) {
13149 handle: this.handles[ index ],
13150 value: this.value()
13152 if ( this.options.values && this.options.values.length ) {
13153 uiHash.value = this.values( index );
13154 uiHash.values = this.values();
13157 //store the last changed value index for reference when handles overlap
13158 this._lastChangedValue = index;
13160 this._trigger( "change", event, uiHash );
13164 value: function( newValue ) {
13165 if ( arguments.length ) {
13166 this.options.value = this._trimAlignValue( newValue );
13167 this._refreshValue();
13168 this._change( null, 0 );
13172 return this._value();
13175 values: function( index, newValue ) {
13180 if ( arguments.length > 1 ) {
13181 this.options.values[ index ] = this._trimAlignValue( newValue );
13182 this._refreshValue();
13183 this._change( null, index );
13187 if ( arguments.length ) {
13188 if ( $.isArray( arguments[ 0 ] ) ) {
13189 vals = this.options.values;
13190 newValues = arguments[ 0 ];
13191 for ( i = 0; i < vals.length; i += 1 ) {
13192 vals[ i ] = this._trimAlignValue( newValues[ i ] );
13193 this._change( null, i );
13195 this._refreshValue();
13197 if ( this.options.values && this.options.values.length ) {
13198 return this._values( index );
13200 return this.value();
13204 return this._values();
13208 _setOption: function( key, value ) {
13212 if ( key === "range" && this.options.range === true ) {
13213 if ( value === "min" ) {
13214 this.options.value = this._values( 0 );
13215 this.options.values = null;
13216 } else if ( value === "max" ) {
13217 this.options.value = this._values( this.options.values.length - 1 );
13218 this.options.values = null;
13222 if ( $.isArray( this.options.values ) ) {
13223 valsLength = this.options.values.length;
13226 if ( key === "disabled" ) {
13227 this.element.toggleClass( "ui-state-disabled", !!value );
13230 this._super( key, value );
13233 case "orientation":
13234 this._detectOrientation();
13236 .removeClass( "ui-slider-horizontal ui-slider-vertical" )
13237 .addClass( "ui-slider-" + this.orientation );
13238 this._refreshValue();
13240 // Reset positioning from previous orientation
13241 this.handles.css( value === "horizontal" ? "bottom" : "left", "" );
13244 this._animateOff = true;
13245 this._refreshValue();
13246 this._change( null, 0 );
13247 this._animateOff = false;
13250 this._animateOff = true;
13251 this._refreshValue();
13252 for ( i = 0; i < valsLength; i += 1 ) {
13253 this._change( null, i );
13255 this._animateOff = false;
13260 this._animateOff = true;
13261 this._calculateNewMax();
13262 this._refreshValue();
13263 this._animateOff = false;
13266 this._animateOff = true;
13268 this._animateOff = false;
13273 //internal value getter
13274 // _value() returns value trimmed by min and max, aligned by step
13275 _value: function() {
13276 var val = this.options.value;
13277 val = this._trimAlignValue( val );
13282 //internal values getter
13283 // _values() returns array of values trimmed by min and max, aligned by step
13284 // _values( index ) returns single value trimmed by min and max, aligned by step
13285 _values: function( index ) {
13290 if ( arguments.length ) {
13291 val = this.options.values[ index ];
13292 val = this._trimAlignValue( val );
13295 } else if ( this.options.values && this.options.values.length ) {
13296 // .slice() creates a copy of the array
13297 // this copy gets trimmed by min and max and then returned
13298 vals = this.options.values.slice();
13299 for ( i = 0; i < vals.length; i += 1) {
13300 vals[ i ] = this._trimAlignValue( vals[ i ] );
13309 // returns the step-aligned value that val is closest to, between (inclusive) min and max
13310 _trimAlignValue: function( val ) {
13311 if ( val <= this._valueMin() ) {
13312 return this._valueMin();
13314 if ( val >= this._valueMax() ) {
13315 return this._valueMax();
13317 var step = ( this.options.step > 0 ) ? this.options.step : 1,
13318 valModStep = (val - this._valueMin()) % step,
13319 alignValue = val - valModStep;
13321 if ( Math.abs(valModStep) * 2 >= step ) {
13322 alignValue += ( valModStep > 0 ) ? step : ( -step );
13325 // Since JavaScript has problems with large floats, round
13326 // the final value to 5 digits after the decimal point (see #4124)
13327 return parseFloat( alignValue.toFixed(5) );
13330 _calculateNewMax: function() {
13331 var remainder = ( this.options.max - this._valueMin() ) % this.options.step;
13332 this.max = this.options.max - remainder;
13335 _valueMin: function() {
13336 return this.options.min;
13339 _valueMax: function() {
13343 _refreshValue: function() {
13344 var lastValPercent, valPercent, value, valueMin, valueMax,
13345 oRange = this.options.range,
13348 animate = ( !this._animateOff ) ? o.animate : false,
13351 if ( this.options.values && this.options.values.length ) {
13352 this.handles.each(function( i ) {
13353 valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100;
13354 _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
13355 $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
13356 if ( that.options.range === true ) {
13357 if ( that.orientation === "horizontal" ) {
13359 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate );
13362 that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
13366 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate );
13369 that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
13373 lastValPercent = valPercent;
13376 value = this.value();
13377 valueMin = this._valueMin();
13378 valueMax = this._valueMax();
13379 valPercent = ( valueMax !== valueMin ) ?
13380 ( value - valueMin ) / ( valueMax - valueMin ) * 100 :
13382 _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
13383 this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
13385 if ( oRange === "min" && this.orientation === "horizontal" ) {
13386 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate );
13388 if ( oRange === "max" && this.orientation === "horizontal" ) {
13389 this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
13391 if ( oRange === "min" && this.orientation === "vertical" ) {
13392 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate );
13394 if ( oRange === "max" && this.orientation === "vertical" ) {
13395 this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
13401 keydown: function( event ) {
13402 var allowed, curVal, newVal, step,
13403 index = $( event.target ).data( "ui-slider-handle-index" );
13405 switch ( event.keyCode ) {
13406 case $.ui.keyCode.HOME:
13407 case $.ui.keyCode.END:
13408 case $.ui.keyCode.PAGE_UP:
13409 case $.ui.keyCode.PAGE_DOWN:
13410 case $.ui.keyCode.UP:
13411 case $.ui.keyCode.RIGHT:
13412 case $.ui.keyCode.DOWN:
13413 case $.ui.keyCode.LEFT:
13414 event.preventDefault();
13415 if ( !this._keySliding ) {
13416 this._keySliding = true;
13417 $( event.target ).addClass( "ui-state-active" );
13418 allowed = this._start( event, index );
13419 if ( allowed === false ) {
13426 step = this.options.step;
13427 if ( this.options.values && this.options.values.length ) {
13428 curVal = newVal = this.values( index );
13430 curVal = newVal = this.value();
13433 switch ( event.keyCode ) {
13434 case $.ui.keyCode.HOME:
13435 newVal = this._valueMin();
13437 case $.ui.keyCode.END:
13438 newVal = this._valueMax();
13440 case $.ui.keyCode.PAGE_UP:
13441 newVal = this._trimAlignValue(
13442 curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages )
13445 case $.ui.keyCode.PAGE_DOWN:
13446 newVal = this._trimAlignValue(
13447 curVal - ( (this._valueMax() - this._valueMin()) / this.numPages ) );
13449 case $.ui.keyCode.UP:
13450 case $.ui.keyCode.RIGHT:
13451 if ( curVal === this._valueMax() ) {
13454 newVal = this._trimAlignValue( curVal + step );
13456 case $.ui.keyCode.DOWN:
13457 case $.ui.keyCode.LEFT:
13458 if ( curVal === this._valueMin() ) {
13461 newVal = this._trimAlignValue( curVal - step );
13465 this._slide( event, index, newVal );
13467 keyup: function( event ) {
13468 var index = $( event.target ).data( "ui-slider-handle-index" );
13470 if ( this._keySliding ) {
13471 this._keySliding = false;
13472 this._stop( event, index );
13473 this._change( event, index );
13474 $( event.target ).removeClass( "ui-state-active" );
13482 * jQuery UI Sortable 1.11.2
13483 * http://jqueryui.com
13485 * Copyright 2014 jQuery Foundation and other contributors
13486 * Released under the MIT license.
13487 * http://jquery.org/license
13489 * http://api.jqueryui.com/sortable/
13493 var sortable = $.widget("ui.sortable", $.ui.mouse, {
13495 widgetEventPrefix: "sort",
13498 appendTo: "parent",
13500 connectWith: false,
13501 containment: false,
13505 forcePlaceholderSize: false,
13506 forceHelperSize: false,
13509 helper: "original",
13512 placeholder: false,
13515 scrollSensitivity: 20,
13518 tolerance: "intersect",
13536 _isOverAxis: function( x, reference, size ) {
13537 return ( x >= reference ) && ( x < ( reference + size ) );
13540 _isFloating: function( item ) {
13541 return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display"));
13544 _create: function() {
13546 var o = this.options;
13547 this.containerCache = {};
13548 this.element.addClass("ui-sortable");
13553 //Let's determine if the items are being displayed horizontally
13554 this.floating = this.items.length ? o.axis === "x" || this._isFloating(this.items[0].item) : false;
13556 //Let's determine the parent's offset
13557 this.offset = this.element.offset();
13559 //Initialize mouse events for interaction
13562 this._setHandleClassName();
13564 //We're ready to go
13569 _setOption: function( key, value ) {
13570 this._super( key, value );
13572 if ( key === "handle" ) {
13573 this._setHandleClassName();
13577 _setHandleClassName: function() {
13578 this.element.find( ".ui-sortable-handle" ).removeClass( "ui-sortable-handle" );
13579 $.each( this.items, function() {
13580 ( this.instance.options.handle ?
13581 this.item.find( this.instance.options.handle ) : this.item )
13582 .addClass( "ui-sortable-handle" );
13586 _destroy: function() {
13588 .removeClass( "ui-sortable ui-sortable-disabled" )
13589 .find( ".ui-sortable-handle" )
13590 .removeClass( "ui-sortable-handle" );
13591 this._mouseDestroy();
13593 for ( var i = this.items.length - 1; i >= 0; i-- ) {
13594 this.items[i].item.removeData(this.widgetName + "-item");
13600 _mouseCapture: function(event, overrideHandle) {
13601 var currentItem = null,
13602 validHandle = false,
13605 if (this.reverting) {
13609 if(this.options.disabled || this.options.type === "static") {
13613 //We have to refresh the items data once first
13614 this._refreshItems(event);
13616 //Find out if the clicked node (or one of its parents) is a actual item in this.items
13617 $(event.target).parents().each(function() {
13618 if($.data(this, that.widgetName + "-item") === that) {
13619 currentItem = $(this);
13623 if($.data(event.target, that.widgetName + "-item") === that) {
13624 currentItem = $(event.target);
13630 if(this.options.handle && !overrideHandle) {
13631 $(this.options.handle, currentItem).find("*").addBack().each(function() {
13632 if(this === event.target) {
13633 validHandle = true;
13641 this.currentItem = currentItem;
13642 this._removeCurrentsFromItems();
13647 _mouseStart: function(event, overrideHandle, noActivation) {
13652 this.currentContainer = this;
13654 //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
13655 this.refreshPositions();
13657 //Create and append the visible helper
13658 this.helper = this._createHelper(event);
13660 //Cache the helper size
13661 this._cacheHelperProportions();
13664 * - Position generation -
13665 * This block generates everything position related - it's the core of draggables.
13668 //Cache the margins of the original element
13669 this._cacheMargins();
13671 //Get the next scrolling parent
13672 this.scrollParent = this.helper.scrollParent();
13674 //The element's absolute position on the page minus margins
13675 this.offset = this.currentItem.offset();
13677 top: this.offset.top - this.margins.top,
13678 left: this.offset.left - this.margins.left
13681 $.extend(this.offset, {
13682 click: { //Where the click happened, relative to the element
13683 left: event.pageX - this.offset.left,
13684 top: event.pageY - this.offset.top
13686 parent: this._getParentOffset(),
13687 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
13690 // Only after we got the offset, we can change the helper's position to absolute
13691 // TODO: Still need to figure out a way to make relative sorting possible
13692 this.helper.css("position", "absolute");
13693 this.cssPosition = this.helper.css("position");
13695 //Generate the original position
13696 this.originalPosition = this._generatePosition(event);
13697 this.originalPageX = event.pageX;
13698 this.originalPageY = event.pageY;
13700 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
13701 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
13703 //Cache the former DOM position
13704 this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };
13706 //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
13707 if(this.helper[0] !== this.currentItem[0]) {
13708 this.currentItem.hide();
13711 //Create the placeholder
13712 this._createPlaceholder();
13714 //Set a containment if given in the options
13715 if(o.containment) {
13716 this._setContainment();
13719 if( o.cursor && o.cursor !== "auto" ) { // cursor option
13720 body = this.document.find( "body" );
13723 this.storedCursor = body.css( "cursor" );
13724 body.css( "cursor", o.cursor );
13726 this.storedStylesheet = $( "<style>*{ cursor: "+o.cursor+" !important; }</style>" ).appendTo( body );
13729 if(o.opacity) { // opacity option
13730 if (this.helper.css("opacity")) {
13731 this._storedOpacity = this.helper.css("opacity");
13733 this.helper.css("opacity", o.opacity);
13736 if(o.zIndex) { // zIndex option
13737 if (this.helper.css("zIndex")) {
13738 this._storedZIndex = this.helper.css("zIndex");
13740 this.helper.css("zIndex", o.zIndex);
13743 //Prepare scrolling
13744 if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") {
13745 this.overflowOffset = this.scrollParent.offset();
13749 this._trigger("start", event, this._uiHash());
13751 //Recache the helper size
13752 if(!this._preserveHelperProportions) {
13753 this._cacheHelperProportions();
13757 //Post "activate" events to possible containers
13758 if( !noActivation ) {
13759 for ( i = this.containers.length - 1; i >= 0; i-- ) {
13760 this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
13764 //Prepare possible droppables
13765 if($.ui.ddmanager) {
13766 $.ui.ddmanager.current = this;
13769 if ($.ui.ddmanager && !o.dropBehaviour) {
13770 $.ui.ddmanager.prepareOffsets(this, event);
13773 this.dragging = true;
13775 this.helper.addClass("ui-sortable-helper");
13776 this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
13781 _mouseDrag: function(event) {
13782 var i, item, itemElement, intersection,
13786 //Compute the helpers position
13787 this.position = this._generatePosition(event);
13788 this.positionAbs = this._convertPositionTo("absolute");
13790 if (!this.lastPositionAbs) {
13791 this.lastPositionAbs = this.positionAbs;
13795 if(this.options.scroll) {
13796 if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") {
13798 if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
13799 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
13800 } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) {
13801 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
13804 if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
13805 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
13806 } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) {
13807 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
13812 if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
13813 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
13814 } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
13815 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
13818 if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
13819 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
13820 } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
13821 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
13826 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
13827 $.ui.ddmanager.prepareOffsets(this, event);
13831 //Regenerate the absolute position used for position checks
13832 this.positionAbs = this._convertPositionTo("absolute");
13834 //Set the helper position
13835 if(!this.options.axis || this.options.axis !== "y") {
13836 this.helper[0].style.left = this.position.left+"px";
13838 if(!this.options.axis || this.options.axis !== "x") {
13839 this.helper[0].style.top = this.position.top+"px";
13843 for (i = this.items.length - 1; i >= 0; i--) {
13845 //Cache variables and intersection, continue if no intersection
13846 item = this.items[i];
13847 itemElement = item.item[0];
13848 intersection = this._intersectsWithPointer(item);
13849 if (!intersection) {
13853 // Only put the placeholder inside the current Container, skip all
13854 // items from other containers. This works because when moving
13855 // an item from one container to another the
13856 // currentContainer is switched before the placeholder is moved.
13858 // Without this, moving items in "sub-sortables" can cause
13859 // the placeholder to jitter between the outer and inner container.
13860 if (item.instance !== this.currentContainer) {
13864 // cannot intersect with itself
13865 // no useless actions that have been done before
13866 // no action if the item moved is the parent of the item checked
13867 if (itemElement !== this.currentItem[0] &&
13868 this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement &&
13869 !$.contains(this.placeholder[0], itemElement) &&
13870 (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true)
13873 this.direction = intersection === 1 ? "down" : "up";
13875 if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) {
13876 this._rearrange(event, item);
13881 this._trigger("change", event, this._uiHash());
13886 //Post events to containers
13887 this._contactContainers(event);
13889 //Interconnect with droppables
13890 if($.ui.ddmanager) {
13891 $.ui.ddmanager.drag(this, event);
13895 this._trigger("sort", event, this._uiHash());
13897 this.lastPositionAbs = this.positionAbs;
13902 _mouseStop: function(event, noPropagation) {
13908 //If we are using droppables, inform the manager about the drop
13909 if ($.ui.ddmanager && !this.options.dropBehaviour) {
13910 $.ui.ddmanager.drop(this, event);
13913 if(this.options.revert) {
13915 cur = this.placeholder.offset(),
13916 axis = this.options.axis,
13919 if ( !axis || axis === "x" ) {
13920 animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollLeft);
13922 if ( !axis || axis === "y" ) {
13923 animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollTop);
13925 this.reverting = true;
13926 $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() {
13927 that._clear(event);
13930 this._clear(event, noPropagation);
13937 cancel: function() {
13939 if(this.dragging) {
13941 this._mouseUp({ target: null });
13943 if(this.options.helper === "original") {
13944 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
13946 this.currentItem.show();
13949 //Post deactivating events to containers
13950 for (var i = this.containers.length - 1; i >= 0; i--){
13951 this.containers[i]._trigger("deactivate", null, this._uiHash(this));
13952 if(this.containers[i].containerCache.over) {
13953 this.containers[i]._trigger("out", null, this._uiHash(this));
13954 this.containers[i].containerCache.over = 0;
13960 if (this.placeholder) {
13961 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
13962 if(this.placeholder[0].parentNode) {
13963 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
13965 if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) {
13966 this.helper.remove();
13976 if(this.domPosition.prev) {
13977 $(this.domPosition.prev).after(this.currentItem);
13979 $(this.domPosition.parent).prepend(this.currentItem);
13987 serialize: function(o) {
13989 var items = this._getItemsAsjQuery(o && o.connected),
13993 $(items).each(function() {
13994 var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/));
13996 str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2]));
14000 if(!str.length && o.key) {
14001 str.push(o.key + "=");
14004 return str.join("&");
14008 toArray: function(o) {
14010 var items = this._getItemsAsjQuery(o && o.connected),
14015 items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); });
14020 /* Be careful with the following core functions */
14021 _intersectsWith: function(item) {
14023 var x1 = this.positionAbs.left,
14024 x2 = x1 + this.helperProportions.width,
14025 y1 = this.positionAbs.top,
14026 y2 = y1 + this.helperProportions.height,
14028 r = l + item.width,
14030 b = t + item.height,
14031 dyClick = this.offset.click.top,
14032 dxClick = this.offset.click.left,
14033 isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ),
14034 isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ),
14035 isOverElement = isOverElementHeight && isOverElementWidth;
14037 if ( this.options.tolerance === "pointer" ||
14038 this.options.forcePointerForContainers ||
14039 (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"])
14041 return isOverElement;
14044 return (l < x1 + (this.helperProportions.width / 2) && // Right Half
14045 x2 - (this.helperProportions.width / 2) < r && // Left Half
14046 t < y1 + (this.helperProportions.height / 2) && // Bottom Half
14047 y2 - (this.helperProportions.height / 2) < b ); // Top Half
14052 _intersectsWithPointer: function(item) {
14054 var isOverElementHeight = (this.options.axis === "x") || this._isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
14055 isOverElementWidth = (this.options.axis === "y") || this._isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
14056 isOverElement = isOverElementHeight && isOverElementWidth,
14057 verticalDirection = this._getDragVerticalDirection(),
14058 horizontalDirection = this._getDragHorizontalDirection();
14060 if (!isOverElement) {
14064 return this.floating ?
14065 ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 )
14066 : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) );
14070 _intersectsWithSides: function(item) {
14072 var isOverBottomHalf = this._isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
14073 isOverRightHalf = this._isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
14074 verticalDirection = this._getDragVerticalDirection(),
14075 horizontalDirection = this._getDragHorizontalDirection();
14077 if (this.floating && horizontalDirection) {
14078 return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf));
14080 return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf));
14085 _getDragVerticalDirection: function() {
14086 var delta = this.positionAbs.top - this.lastPositionAbs.top;
14087 return delta !== 0 && (delta > 0 ? "down" : "up");
14090 _getDragHorizontalDirection: function() {
14091 var delta = this.positionAbs.left - this.lastPositionAbs.left;
14092 return delta !== 0 && (delta > 0 ? "right" : "left");
14095 refresh: function(event) {
14096 this._refreshItems(event);
14097 this._setHandleClassName();
14098 this.refreshPositions();
14102 _connectWith: function() {
14103 var options = this.options;
14104 return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith;
14107 _getItemsAsjQuery: function(connected) {
14109 var i, j, cur, inst,
14112 connectWith = this._connectWith();
14114 if(connectWith && connected) {
14115 for (i = connectWith.length - 1; i >= 0; i--){
14116 cur = $(connectWith[i]);
14117 for ( j = cur.length - 1; j >= 0; j--){
14118 inst = $.data(cur[j], this.widgetFullName);
14119 if(inst && inst !== this && !inst.options.disabled) {
14120 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]);
14126 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]);
14128 function addItems() {
14129 items.push( this );
14131 for (i = queries.length - 1; i >= 0; i--){
14132 queries[i][0].each( addItems );
14139 _removeCurrentsFromItems: function() {
14141 var list = this.currentItem.find(":data(" + this.widgetName + "-item)");
14143 this.items = $.grep(this.items, function (item) {
14144 for (var j=0; j < list.length; j++) {
14145 if(list[j] === item.item[0]) {
14154 _refreshItems: function(event) {
14157 this.containers = [this];
14159 var i, j, cur, inst, targetData, _queries, item, queriesLength,
14160 items = this.items,
14161 queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]],
14162 connectWith = this._connectWith();
14164 if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down
14165 for (i = connectWith.length - 1; i >= 0; i--){
14166 cur = $(connectWith[i]);
14167 for (j = cur.length - 1; j >= 0; j--){
14168 inst = $.data(cur[j], this.widgetFullName);
14169 if(inst && inst !== this && !inst.options.disabled) {
14170 queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
14171 this.containers.push(inst);
14177 for (i = queries.length - 1; i >= 0; i--) {
14178 targetData = queries[i][1];
14179 _queries = queries[i][0];
14181 for (j=0, queriesLength = _queries.length; j < queriesLength; j++) {
14182 item = $(_queries[j]);
14184 item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager)
14188 instance: targetData,
14189 width: 0, height: 0,
14197 refreshPositions: function(fast) {
14199 //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
14200 if(this.offsetParent && this.helper) {
14201 this.offset.parent = this._getParentOffset();
14206 for (i = this.items.length - 1; i >= 0; i--){
14207 item = this.items[i];
14209 //We ignore calculating positions of all connected containers when we're not over them
14210 if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) {
14214 t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
14217 item.width = t.outerWidth();
14218 item.height = t.outerHeight();
14222 item.left = p.left;
14226 if(this.options.custom && this.options.custom.refreshContainers) {
14227 this.options.custom.refreshContainers.call(this);
14229 for (i = this.containers.length - 1; i >= 0; i--){
14230 p = this.containers[i].element.offset();
14231 this.containers[i].containerCache.left = p.left;
14232 this.containers[i].containerCache.top = p.top;
14233 this.containers[i].containerCache.width = this.containers[i].element.outerWidth();
14234 this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
14241 _createPlaceholder: function(that) {
14242 that = that || this;
14246 if(!o.placeholder || o.placeholder.constructor === String) {
14247 className = o.placeholder;
14249 element: function() {
14251 var nodeName = that.currentItem[0].nodeName.toLowerCase(),
14252 element = $( "<" + nodeName + ">", that.document[0] )
14253 .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder")
14254 .removeClass("ui-sortable-helper");
14256 if ( nodeName === "tr" ) {
14257 that.currentItem.children().each(function() {
14258 $( "<td> </td>", that.document[0] )
14259 .attr( "colspan", $( this ).attr( "colspan" ) || 1 )
14260 .appendTo( element );
14262 } else if ( nodeName === "img" ) {
14263 element.attr( "src", that.currentItem.attr( "src" ) );
14266 if ( !className ) {
14267 element.css( "visibility", "hidden" );
14272 update: function(container, p) {
14274 // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that
14275 // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified
14276 if(className && !o.forcePlaceholderSize) {
14280 //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
14281 if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); }
14282 if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); }
14287 //Create the placeholder
14288 that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem));
14290 //Append it after the actual current item
14291 that.currentItem.after(that.placeholder);
14293 //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
14294 o.placeholder.update(that, that.placeholder);
14298 _contactContainers: function(event) {
14299 var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom, floating, axis,
14300 innermostContainer = null,
14301 innermostIndex = null;
14303 // get innermost container that intersects with item
14304 for (i = this.containers.length - 1; i >= 0; i--) {
14306 // never consider a container that's located within the item itself
14307 if($.contains(this.currentItem[0], this.containers[i].element[0])) {
14311 if(this._intersectsWith(this.containers[i].containerCache)) {
14313 // if we've already found a container and it's more "inner" than this, then continue
14314 if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) {
14318 innermostContainer = this.containers[i];
14319 innermostIndex = i;
14322 // container doesn't intersect. trigger "out" event if necessary
14323 if(this.containers[i].containerCache.over) {
14324 this.containers[i]._trigger("out", event, this._uiHash(this));
14325 this.containers[i].containerCache.over = 0;
14331 // if no intersecting containers found, return
14332 if(!innermostContainer) {
14336 // move the item into the container if it's not there already
14337 if(this.containers.length === 1) {
14338 if (!this.containers[innermostIndex].containerCache.over) {
14339 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
14340 this.containers[innermostIndex].containerCache.over = 1;
14344 //When entering a new container, we will find the item with the least distance and append our item near it
14346 itemWithLeastDistance = null;
14347 floating = innermostContainer.floating || this._isFloating(this.currentItem);
14348 posProperty = floating ? "left" : "top";
14349 sizeProperty = floating ? "width" : "height";
14350 axis = floating ? "clientX" : "clientY";
14352 for (j = this.items.length - 1; j >= 0; j--) {
14353 if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) {
14356 if(this.items[j].item[0] === this.currentItem[0]) {
14360 cur = this.items[j].item.offset()[posProperty];
14361 nearBottom = false;
14362 if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) {
14366 if ( Math.abs( event[ axis ] - cur ) < dist ) {
14367 dist = Math.abs( event[ axis ] - cur );
14368 itemWithLeastDistance = this.items[ j ];
14369 this.direction = nearBottom ? "up": "down";
14373 //Check if dropOnEmpty is enabled
14374 if(!itemWithLeastDistance && !this.options.dropOnEmpty) {
14378 if(this.currentContainer === this.containers[innermostIndex]) {
14379 if ( !this.currentContainer.containerCache.over ) {
14380 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() );
14381 this.currentContainer.containerCache.over = 1;
14386 itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true);
14387 this._trigger("change", event, this._uiHash());
14388 this.containers[innermostIndex]._trigger("change", event, this._uiHash(this));
14389 this.currentContainer = this.containers[innermostIndex];
14391 //Update the placeholder
14392 this.options.placeholder.update(this.currentContainer, this.placeholder);
14394 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
14395 this.containers[innermostIndex].containerCache.over = 1;
14401 _createHelper: function(event) {
14403 var o = this.options,
14404 helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem);
14406 //Add the helper to the DOM if that didn't happen already
14407 if(!helper.parents("body").length) {
14408 $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
14411 if(helper[0] === this.currentItem[0]) {
14412 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") };
14415 if(!helper[0].style.width || o.forceHelperSize) {
14416 helper.width(this.currentItem.width());
14418 if(!helper[0].style.height || o.forceHelperSize) {
14419 helper.height(this.currentItem.height());
14426 _adjustOffsetFromHelper: function(obj) {
14427 if (typeof obj === "string") {
14428 obj = obj.split(" ");
14430 if ($.isArray(obj)) {
14431 obj = {left: +obj[0], top: +obj[1] || 0};
14433 if ("left" in obj) {
14434 this.offset.click.left = obj.left + this.margins.left;
14436 if ("right" in obj) {
14437 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
14439 if ("top" in obj) {
14440 this.offset.click.top = obj.top + this.margins.top;
14442 if ("bottom" in obj) {
14443 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
14447 _getParentOffset: function() {
14450 //Get the offsetParent and cache its position
14451 this.offsetParent = this.helper.offsetParent();
14452 var po = this.offsetParent.offset();
14454 // This is a special case where we need to modify a offset calculated on start, since the following happened:
14455 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
14456 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
14457 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
14458 if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
14459 po.left += this.scrollParent.scrollLeft();
14460 po.top += this.scrollParent.scrollTop();
14463 // This needs to be actually done for all browsers, since pageX/pageY includes this information
14464 // with an ugly IE fix
14465 if( this.offsetParent[0] === document.body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
14466 po = { top: 0, left: 0 };
14470 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
14471 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
14476 _getRelativeOffset: function() {
14478 if(this.cssPosition === "relative") {
14479 var p = this.currentItem.position();
14481 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
14482 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
14485 return { top: 0, left: 0 };
14490 _cacheMargins: function() {
14492 left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
14493 top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
14497 _cacheHelperProportions: function() {
14498 this.helperProportions = {
14499 width: this.helper.outerWidth(),
14500 height: this.helper.outerHeight()
14504 _setContainment: function() {
14508 if(o.containment === "parent") {
14509 o.containment = this.helper[0].parentNode;
14511 if(o.containment === "document" || o.containment === "window") {
14512 this.containment = [
14513 0 - this.offset.relative.left - this.offset.parent.left,
14514 0 - this.offset.relative.top - this.offset.parent.top,
14515 $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left,
14516 ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
14520 if(!(/^(document|window|parent)$/).test(o.containment)) {
14521 ce = $(o.containment)[0];
14522 co = $(o.containment).offset();
14523 over = ($(ce).css("overflow") !== "hidden");
14525 this.containment = [
14526 co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
14527 co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
14528 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,
14529 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
14535 _convertPositionTo: function(d, pos) {
14538 pos = this.position;
14540 var mod = d === "absolute" ? 1 : -1,
14541 scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent,
14542 scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
14546 pos.top + // The absolute mouse position
14547 this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
14548 this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
14549 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
14552 pos.left + // The absolute mouse position
14553 this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
14554 this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
14555 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
14561 _generatePosition: function(event) {
14565 pageX = event.pageX,
14566 pageY = event.pageY,
14567 scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
14569 // This is another very weird special case that only happens for relative elements:
14570 // 1. If the css position is relative
14571 // 2. and the scroll parent is the document or similar to the offset parent
14572 // we have to refresh the relative offset during the scroll so there are no jumps
14573 if(this.cssPosition === "relative" && !(this.scrollParent[0] !== document && this.scrollParent[0] !== this.offsetParent[0])) {
14574 this.offset.relative = this._getRelativeOffset();
14578 * - Position constraining -
14579 * Constrain the position to a mix of grid, containment.
14582 if(this.originalPosition) { //If we are not dragging yet, we won't check for options
14584 if(this.containment) {
14585 if(event.pageX - this.offset.click.left < this.containment[0]) {
14586 pageX = this.containment[0] + this.offset.click.left;
14588 if(event.pageY - this.offset.click.top < this.containment[1]) {
14589 pageY = this.containment[1] + this.offset.click.top;
14591 if(event.pageX - this.offset.click.left > this.containment[2]) {
14592 pageX = this.containment[2] + this.offset.click.left;
14594 if(event.pageY - this.offset.click.top > this.containment[3]) {
14595 pageY = this.containment[3] + this.offset.click.top;
14600 top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
14601 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;
14603 left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
14604 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;
14611 pageY - // The absolute mouse position
14612 this.offset.click.top - // Click offset (relative to the element)
14613 this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
14614 this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
14615 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
14618 pageX - // The absolute mouse position
14619 this.offset.click.left - // Click offset (relative to the element)
14620 this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
14621 this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
14622 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
14628 _rearrange: function(event, i, a, hardRefresh) {
14630 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));
14632 //Various things done here to improve the performance:
14633 // 1. we create a setTimeout, that calls refreshPositions
14634 // 2. on the instance, we have a counter variable, that get's higher after every append
14635 // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
14636 // 4. this lets only the last addition to the timeout stack through
14637 this.counter = this.counter ? ++this.counter : 1;
14638 var counter = this.counter;
14640 this._delay(function() {
14641 if(counter === this.counter) {
14642 this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
14648 _clear: function(event, noPropagation) {
14650 this.reverting = false;
14651 // We delay all events that have to be triggered to after the point where the placeholder has been removed and
14652 // everything else normalized again
14654 delayedTriggers = [];
14656 // We first have to update the dom position of the actual currentItem
14657 // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
14658 if(!this._noFinalSort && this.currentItem.parent().length) {
14659 this.placeholder.before(this.currentItem);
14661 this._noFinalSort = null;
14663 if(this.helper[0] === this.currentItem[0]) {
14664 for(i in this._storedCSS) {
14665 if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") {
14666 this._storedCSS[i] = "";
14669 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
14671 this.currentItem.show();
14674 if(this.fromOutside && !noPropagation) {
14675 delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
14677 if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) {
14678 delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed
14681 // Check if the items Container has Changed and trigger appropriate
14683 if (this !== this.currentContainer) {
14684 if(!noPropagation) {
14685 delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); });
14686 delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
14687 delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
14692 //Post events to containers
14693 function delayEvent( type, instance, container ) {
14694 return function( event ) {
14695 container._trigger( type, event, instance._uiHash( instance ) );
14698 for (i = this.containers.length - 1; i >= 0; i--){
14699 if (!noPropagation) {
14700 delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) );
14702 if(this.containers[i].containerCache.over) {
14703 delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) );
14704 this.containers[i].containerCache.over = 0;
14708 //Do what was originally in plugins
14709 if ( this.storedCursor ) {
14710 this.document.find( "body" ).css( "cursor", this.storedCursor );
14711 this.storedStylesheet.remove();
14713 if(this._storedOpacity) {
14714 this.helper.css("opacity", this._storedOpacity);
14716 if(this._storedZIndex) {
14717 this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex);
14720 this.dragging = false;
14722 if(!noPropagation) {
14723 this._trigger("beforeStop", event, this._uiHash());
14726 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
14727 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
14729 if ( !this.cancelHelperRemoval ) {
14730 if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
14731 this.helper.remove();
14733 this.helper = null;
14736 if(!noPropagation) {
14737 for (i=0; i < delayedTriggers.length; i++) {
14738 delayedTriggers[i].call(this, event);
14739 } //Trigger all delayed events
14740 this._trigger("stop", event, this._uiHash());
14743 this.fromOutside = false;
14744 return !this.cancelHelperRemoval;
14748 _trigger: function() {
14749 if ($.Widget.prototype._trigger.apply(this, arguments) === false) {
14754 _uiHash: function(_inst) {
14755 var inst = _inst || this;
14757 helper: inst.helper,
14758 placeholder: inst.placeholder || $([]),
14759 position: inst.position,
14760 originalPosition: inst.originalPosition,
14761 offset: inst.positionAbs,
14762 item: inst.currentItem,
14763 sender: _inst ? _inst.element : null
14771 * jQuery UI Spinner 1.11.2
14772 * http://jqueryui.com
14774 * Copyright 2014 jQuery Foundation and other contributors
14775 * Released under the MIT license.
14776 * http://jquery.org/license
14778 * http://api.jqueryui.com/spinner/
14782 function spinner_modifier( fn ) {
14783 return function() {
14784 var previous = this.element.val();
14785 fn.apply( this, arguments );
14787 if ( previous !== this.element.val() ) {
14788 this._trigger( "change" );
14793 var spinner = $.widget( "ui.spinner", {
14795 defaultElement: "<input>",
14796 widgetEventPrefix: "spin",
14800 down: "ui-icon-triangle-1-s",
14801 up: "ui-icon-triangle-1-n"
14806 numberFormat: null,
14816 _create: function() {
14817 // handle string values that need to be parsed
14818 this._setOption( "max", this.options.max );
14819 this._setOption( "min", this.options.min );
14820 this._setOption( "step", this.options.step );
14822 // Only format if there is a value, prevents the field from being marked
14823 // as invalid in Firefox, see #9573.
14824 if ( this.value() !== "" ) {
14825 // Format the value, but don't constrain.
14826 this._value( this.element.val(), true );
14830 this._on( this._events );
14833 // turning off autocomplete prevents the browser from remembering the
14834 // value when navigating through history, so we re-enable autocomplete
14835 // if the page is unloaded before the widget is destroyed. #7790
14836 this._on( this.window, {
14837 beforeunload: function() {
14838 this.element.removeAttr( "autocomplete" );
14843 _getCreateOptions: function() {
14845 element = this.element;
14847 $.each( [ "min", "max", "step" ], function( i, option ) {
14848 var value = element.attr( option );
14849 if ( value !== undefined && value.length ) {
14850 options[ option ] = value;
14858 keydown: function( event ) {
14859 if ( this._start( event ) && this._keydown( event ) ) {
14860 event.preventDefault();
14864 focus: function() {
14865 this.previous = this.element.val();
14867 blur: function( event ) {
14868 if ( this.cancelBlur ) {
14869 delete this.cancelBlur;
14875 if ( this.previous !== this.element.val() ) {
14876 this._trigger( "change", event );
14879 mousewheel: function( event, delta ) {
14883 if ( !this.spinning && !this._start( event ) ) {
14887 this._spin( (delta > 0 ? 1 : -1) * this.options.step, event );
14888 clearTimeout( this.mousewheelTimer );
14889 this.mousewheelTimer = this._delay(function() {
14890 if ( this.spinning ) {
14891 this._stop( event );
14894 event.preventDefault();
14896 "mousedown .ui-spinner-button": function( event ) {
14899 // We never want the buttons to have focus; whenever the user is
14900 // interacting with the spinner, the focus should be on the input.
14901 // If the input is focused then this.previous is properly set from
14902 // when the input first received focus. If the input is not focused
14903 // then we need to set this.previous based on the value before spinning.
14904 previous = this.element[0] === this.document[0].activeElement ?
14905 this.previous : this.element.val();
14906 function checkFocus() {
14907 var isActive = this.element[0] === this.document[0].activeElement;
14909 this.element.focus();
14910 this.previous = previous;
14912 // IE sets focus asynchronously, so we need to check if focus
14913 // moved off of the input because the user clicked on the button.
14914 this._delay(function() {
14915 this.previous = previous;
14920 // ensure focus is on (or stays on) the text field
14921 event.preventDefault();
14922 checkFocus.call( this );
14925 // IE doesn't prevent moving focus even with event.preventDefault()
14926 // so we set a flag to know when we should ignore the blur event
14927 // and check (again) if focus moved off of the input.
14928 this.cancelBlur = true;
14929 this._delay(function() {
14930 delete this.cancelBlur;
14931 checkFocus.call( this );
14934 if ( this._start( event ) === false ) {
14938 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
14940 "mouseup .ui-spinner-button": "_stop",
14941 "mouseenter .ui-spinner-button": function( event ) {
14942 // button will add ui-state-active if mouse was down while mouseleave and kept down
14943 if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
14947 if ( this._start( event ) === false ) {
14950 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
14952 // TODO: do we really want to consider this a stop?
14953 // shouldn't we just stop the repeater and wait until mouseup before
14954 // we trigger the stop event?
14955 "mouseleave .ui-spinner-button": "_stop"
14958 _draw: function() {
14959 var uiSpinner = this.uiSpinner = this.element
14960 .addClass( "ui-spinner-input" )
14961 .attr( "autocomplete", "off" )
14962 .wrap( this._uiSpinnerHtml() )
14965 .append( this._buttonHtml() );
14967 this.element.attr( "role", "spinbutton" );
14970 this.buttons = uiSpinner.find( ".ui-spinner-button" )
14971 .attr( "tabIndex", -1 )
14973 .removeClass( "ui-corner-all" );
14975 // IE 6 doesn't understand height: 50% for the buttons
14976 // unless the wrapper has an explicit height
14977 if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) &&
14978 uiSpinner.height() > 0 ) {
14979 uiSpinner.height( uiSpinner.height() );
14982 // disable spinner if element was already disabled
14983 if ( this.options.disabled ) {
14988 _keydown: function( event ) {
14989 var options = this.options,
14990 keyCode = $.ui.keyCode;
14992 switch ( event.keyCode ) {
14994 this._repeat( null, 1, event );
14997 this._repeat( null, -1, event );
14999 case keyCode.PAGE_UP:
15000 this._repeat( null, options.page, event );
15002 case keyCode.PAGE_DOWN:
15003 this._repeat( null, -options.page, event );
15010 _uiSpinnerHtml: function() {
15011 return "<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>";
15014 _buttonHtml: function() {
15016 "<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>" +
15017 "<span class='ui-icon " + this.options.icons.up + "'>▲</span>" +
15019 "<a class='ui-spinner-button ui-spinner-down ui-corner-br'>" +
15020 "<span class='ui-icon " + this.options.icons.down + "'>▼</span>" +
15024 _start: function( event ) {
15025 if ( !this.spinning && this._trigger( "start", event ) === false ) {
15029 if ( !this.counter ) {
15032 this.spinning = true;
15036 _repeat: function( i, steps, event ) {
15039 clearTimeout( this.timer );
15040 this.timer = this._delay(function() {
15041 this._repeat( 40, steps, event );
15044 this._spin( steps * this.options.step, event );
15047 _spin: function( step, event ) {
15048 var value = this.value() || 0;
15050 if ( !this.counter ) {
15054 value = this._adjustValue( value + step * this._increment( this.counter ) );
15056 if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) {
15057 this._value( value );
15062 _increment: function( i ) {
15063 var incremental = this.options.incremental;
15065 if ( incremental ) {
15066 return $.isFunction( incremental ) ?
15068 Math.floor( i * i * i / 50000 - i * i / 500 + 17 * i / 200 + 1 );
15074 _precision: function() {
15075 var precision = this._precisionOf( this.options.step );
15076 if ( this.options.min !== null ) {
15077 precision = Math.max( precision, this._precisionOf( this.options.min ) );
15082 _precisionOf: function( num ) {
15083 var str = num.toString(),
15084 decimal = str.indexOf( "." );
15085 return decimal === -1 ? 0 : str.length - decimal - 1;
15088 _adjustValue: function( value ) {
15089 var base, aboveMin,
15090 options = this.options;
15092 // make sure we're at a valid step
15093 // - find out where we are relative to the base (min or 0)
15094 base = options.min !== null ? options.min : 0;
15095 aboveMin = value - base;
15096 // - round to the nearest step
15097 aboveMin = Math.round(aboveMin / options.step) * options.step;
15098 // - rounding is based on 0, so adjust back to our base
15099 value = base + aboveMin;
15101 // fix precision from bad JS floating point math
15102 value = parseFloat( value.toFixed( this._precision() ) );
15105 if ( options.max !== null && value > options.max) {
15106 return options.max;
15108 if ( options.min !== null && value < options.min ) {
15109 return options.min;
15115 _stop: function( event ) {
15116 if ( !this.spinning ) {
15120 clearTimeout( this.timer );
15121 clearTimeout( this.mousewheelTimer );
15123 this.spinning = false;
15124 this._trigger( "stop", event );
15127 _setOption: function( key, value ) {
15128 if ( key === "culture" || key === "numberFormat" ) {
15129 var prevValue = this._parse( this.element.val() );
15130 this.options[ key ] = value;
15131 this.element.val( this._format( prevValue ) );
15135 if ( key === "max" || key === "min" || key === "step" ) {
15136 if ( typeof value === "string" ) {
15137 value = this._parse( value );
15140 if ( key === "icons" ) {
15141 this.buttons.first().find( ".ui-icon" )
15142 .removeClass( this.options.icons.up )
15143 .addClass( value.up );
15144 this.buttons.last().find( ".ui-icon" )
15145 .removeClass( this.options.icons.down )
15146 .addClass( value.down );
15149 this._super( key, value );
15151 if ( key === "disabled" ) {
15152 this.widget().toggleClass( "ui-state-disabled", !!value );
15153 this.element.prop( "disabled", !!value );
15154 this.buttons.button( value ? "disable" : "enable" );
15158 _setOptions: spinner_modifier(function( options ) {
15159 this._super( options );
15162 _parse: function( val ) {
15163 if ( typeof val === "string" && val !== "" ) {
15164 val = window.Globalize && this.options.numberFormat ?
15165 Globalize.parseFloat( val, 10, this.options.culture ) : +val;
15167 return val === "" || isNaN( val ) ? null : val;
15170 _format: function( value ) {
15171 if ( value === "" ) {
15174 return window.Globalize && this.options.numberFormat ?
15175 Globalize.format( value, this.options.numberFormat, this.options.culture ) :
15179 _refresh: function() {
15180 this.element.attr({
15181 "aria-valuemin": this.options.min,
15182 "aria-valuemax": this.options.max,
15183 // TODO: what should we do with values that can't be parsed?
15184 "aria-valuenow": this._parse( this.element.val() )
15188 isValid: function() {
15189 var value = this.value();
15192 if ( value === null ) {
15196 // if value gets adjusted, it's invalid
15197 return value === this._adjustValue( value );
15200 // update the value without triggering change
15201 _value: function( value, allowAny ) {
15203 if ( value !== "" ) {
15204 parsed = this._parse( value );
15205 if ( parsed !== null ) {
15207 parsed = this._adjustValue( parsed );
15209 value = this._format( parsed );
15212 this.element.val( value );
15216 _destroy: function() {
15218 .removeClass( "ui-spinner-input" )
15219 .prop( "disabled", false )
15220 .removeAttr( "autocomplete" )
15221 .removeAttr( "role" )
15222 .removeAttr( "aria-valuemin" )
15223 .removeAttr( "aria-valuemax" )
15224 .removeAttr( "aria-valuenow" );
15225 this.uiSpinner.replaceWith( this.element );
15228 stepUp: spinner_modifier(function( steps ) {
15229 this._stepUp( steps );
15231 _stepUp: function( steps ) {
15232 if ( this._start() ) {
15233 this._spin( (steps || 1) * this.options.step );
15238 stepDown: spinner_modifier(function( steps ) {
15239 this._stepDown( steps );
15241 _stepDown: function( steps ) {
15242 if ( this._start() ) {
15243 this._spin( (steps || 1) * -this.options.step );
15248 pageUp: spinner_modifier(function( pages ) {
15249 this._stepUp( (pages || 1) * this.options.page );
15252 pageDown: spinner_modifier(function( pages ) {
15253 this._stepDown( (pages || 1) * this.options.page );
15256 value: function( newVal ) {
15257 if ( !arguments.length ) {
15258 return this._parse( this.element.val() );
15260 spinner_modifier( this._value ).call( this, newVal );
15263 widget: function() {
15264 return this.uiSpinner;
15270 * jQuery UI Tabs 1.11.2
15271 * http://jqueryui.com
15273 * Copyright 2014 jQuery Foundation and other contributors
15274 * Released under the MIT license.
15275 * http://jquery.org/license
15277 * http://api.jqueryui.com/tabs/
15281 var tabs = $.widget( "ui.tabs", {
15286 collapsible: false,
15288 heightStyle: "content",
15294 beforeActivate: null,
15299 _isLocal: (function() {
15300 var rhash = /#.*$/;
15302 return function( anchor ) {
15303 var anchorUrl, locationUrl;
15306 // IE7 doesn't normalize the href property when set via script (#9317)
15307 anchor = anchor.cloneNode( false );
15309 anchorUrl = anchor.href.replace( rhash, "" );
15310 locationUrl = location.href.replace( rhash, "" );
15312 // decoding may throw an error if the URL isn't UTF-8 (#9518)
15314 anchorUrl = decodeURIComponent( anchorUrl );
15315 } catch ( error ) {}
15317 locationUrl = decodeURIComponent( locationUrl );
15318 } catch ( error ) {}
15320 return anchor.hash.length > 1 && anchorUrl === locationUrl;
15324 _create: function() {
15326 options = this.options;
15328 this.running = false;
15331 .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" )
15332 .toggleClass( "ui-tabs-collapsible", options.collapsible );
15334 this._processTabs();
15335 options.active = this._initialActive();
15337 // Take disabling tabs via class attribute from HTML
15338 // into account and update option properly.
15339 if ( $.isArray( options.disabled ) ) {
15340 options.disabled = $.unique( options.disabled.concat(
15341 $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
15342 return that.tabs.index( li );
15347 // check for length avoids error when initializing empty list
15348 if ( this.options.active !== false && this.anchors.length ) {
15349 this.active = this._findActive( options.active );
15356 if ( this.active.length ) {
15357 this.load( options.active );
15361 _initialActive: function() {
15362 var active = this.options.active,
15363 collapsible = this.options.collapsible,
15364 locationHash = location.hash.substring( 1 );
15366 if ( active === null ) {
15367 // check the fragment identifier in the URL
15368 if ( locationHash ) {
15369 this.tabs.each(function( i, tab ) {
15370 if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
15377 // check for a tab marked active via a class
15378 if ( active === null ) {
15379 active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
15382 // no active tab, set to false
15383 if ( active === null || active === -1 ) {
15384 active = this.tabs.length ? 0 : false;
15388 // handle numbers: negative, out of range
15389 if ( active !== false ) {
15390 active = this.tabs.index( this.tabs.eq( active ) );
15391 if ( active === -1 ) {
15392 active = collapsible ? false : 0;
15396 // don't allow collapsible: false and active: false
15397 if ( !collapsible && active === false && this.anchors.length ) {
15404 _getCreateEventData: function() {
15407 panel: !this.active.length ? $() : this._getPanelForTab( this.active )
15411 _tabKeydown: function( event ) {
15412 var focusedTab = $( this.document[0].activeElement ).closest( "li" ),
15413 selectedIndex = this.tabs.index( focusedTab ),
15414 goingForward = true;
15416 if ( this._handlePageNav( event ) ) {
15420 switch ( event.keyCode ) {
15421 case $.ui.keyCode.RIGHT:
15422 case $.ui.keyCode.DOWN:
15425 case $.ui.keyCode.UP:
15426 case $.ui.keyCode.LEFT:
15427 goingForward = false;
15430 case $.ui.keyCode.END:
15431 selectedIndex = this.anchors.length - 1;
15433 case $.ui.keyCode.HOME:
15436 case $.ui.keyCode.SPACE:
15437 // Activate only, no collapsing
15438 event.preventDefault();
15439 clearTimeout( this.activating );
15440 this._activate( selectedIndex );
15442 case $.ui.keyCode.ENTER:
15443 // Toggle (cancel delayed activation, allow collapsing)
15444 event.preventDefault();
15445 clearTimeout( this.activating );
15446 // Determine if we should collapse or activate
15447 this._activate( selectedIndex === this.options.active ? false : selectedIndex );
15453 // Focus the appropriate tab, based on which key was pressed
15454 event.preventDefault();
15455 clearTimeout( this.activating );
15456 selectedIndex = this._focusNextTab( selectedIndex, goingForward );
15458 // Navigating with control key will prevent automatic activation
15459 if ( !event.ctrlKey ) {
15460 // Update aria-selected immediately so that AT think the tab is already selected.
15461 // Otherwise AT may confuse the user by stating that they need to activate the tab,
15462 // but the tab will already be activated by the time the announcement finishes.
15463 focusedTab.attr( "aria-selected", "false" );
15464 this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
15466 this.activating = this._delay(function() {
15467 this.option( "active", selectedIndex );
15472 _panelKeydown: function( event ) {
15473 if ( this._handlePageNav( event ) ) {
15477 // Ctrl+up moves focus to the current tab
15478 if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
15479 event.preventDefault();
15480 this.active.focus();
15484 // Alt+page up/down moves focus to the previous/next tab (and activates)
15485 _handlePageNav: function( event ) {
15486 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
15487 this._activate( this._focusNextTab( this.options.active - 1, false ) );
15490 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
15491 this._activate( this._focusNextTab( this.options.active + 1, true ) );
15496 _findNextTab: function( index, goingForward ) {
15497 var lastTabIndex = this.tabs.length - 1;
15499 function constrain() {
15500 if ( index > lastTabIndex ) {
15504 index = lastTabIndex;
15509 while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
15510 index = goingForward ? index + 1 : index - 1;
15516 _focusNextTab: function( index, goingForward ) {
15517 index = this._findNextTab( index, goingForward );
15518 this.tabs.eq( index ).focus();
15522 _setOption: function( key, value ) {
15523 if ( key === "active" ) {
15524 // _activate() will handle invalid values and update this.options
15525 this._activate( value );
15529 if ( key === "disabled" ) {
15530 // don't use the widget factory's disabled handling
15531 this._setupDisabled( value );
15535 this._super( key, value);
15537 if ( key === "collapsible" ) {
15538 this.element.toggleClass( "ui-tabs-collapsible", value );
15539 // Setting collapsible: false while collapsed; open first panel
15540 if ( !value && this.options.active === false ) {
15541 this._activate( 0 );
15545 if ( key === "event" ) {
15546 this._setupEvents( value );
15549 if ( key === "heightStyle" ) {
15550 this._setupHeightStyle( value );
15554 _sanitizeSelector: function( hash ) {
15555 return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
15558 refresh: function() {
15559 var options = this.options,
15560 lis = this.tablist.children( ":has(a[href])" );
15562 // get disabled tabs from class attribute from HTML
15563 // this will get converted to a boolean if needed in _refresh()
15564 options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
15565 return lis.index( tab );
15568 this._processTabs();
15570 // was collapsed or no tabs
15571 if ( options.active === false || !this.anchors.length ) {
15572 options.active = false;
15574 // was active, but active tab is gone
15575 } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
15576 // all remaining tabs are disabled
15577 if ( this.tabs.length === options.disabled.length ) {
15578 options.active = false;
15580 // activate previous tab
15582 this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
15584 // was active, active tab still exists
15586 // make sure active index is correct
15587 options.active = this.tabs.index( this.active );
15593 _refresh: function() {
15594 this._setupDisabled( this.options.disabled );
15595 this._setupEvents( this.options.event );
15596 this._setupHeightStyle( this.options.heightStyle );
15598 this.tabs.not( this.active ).attr({
15599 "aria-selected": "false",
15600 "aria-expanded": "false",
15603 this.panels.not( this._getPanelForTab( this.active ) )
15606 "aria-hidden": "true"
15609 // Make sure one tab is in the tab order
15610 if ( !this.active.length ) {
15611 this.tabs.eq( 0 ).attr( "tabIndex", 0 );
15614 .addClass( "ui-tabs-active ui-state-active" )
15616 "aria-selected": "true",
15617 "aria-expanded": "true",
15620 this._getPanelForTab( this.active )
15623 "aria-hidden": "false"
15628 _processTabs: function() {
15630 prevTabs = this.tabs,
15631 prevAnchors = this.anchors,
15632 prevPanels = this.panels;
15634 this.tablist = this._getList()
15635 .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
15636 .attr( "role", "tablist" )
15638 // Prevent users from focusing disabled tabs via click
15639 .delegate( "> li", "mousedown" + this.eventNamespace, function( event ) {
15640 if ( $( this ).is( ".ui-state-disabled" ) ) {
15641 event.preventDefault();
15646 // Preventing the default action in mousedown doesn't prevent IE
15647 // from focusing the element, so if the anchor gets focused, blur.
15648 // We don't have to worry about focusing the previously focused
15649 // element since clicking on a non-focusable element should focus
15650 // the body anyway.
15651 .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() {
15652 if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
15657 this.tabs = this.tablist.find( "> li:has(a[href])" )
15658 .addClass( "ui-state-default ui-corner-top" )
15664 this.anchors = this.tabs.map(function() {
15665 return $( "a", this )[ 0 ];
15667 .addClass( "ui-tabs-anchor" )
15669 role: "presentation",
15675 this.anchors.each(function( i, anchor ) {
15676 var selector, panel, panelId,
15677 anchorId = $( anchor ).uniqueId().attr( "id" ),
15678 tab = $( anchor ).closest( "li" ),
15679 originalAriaControls = tab.attr( "aria-controls" );
15682 if ( that._isLocal( anchor ) ) {
15683 selector = anchor.hash;
15684 panelId = selector.substring( 1 );
15685 panel = that.element.find( that._sanitizeSelector( selector ) );
15688 // If the tab doesn't already have aria-controls,
15689 // generate an id by using a throw-away element
15690 panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id;
15691 selector = "#" + panelId;
15692 panel = that.element.find( selector );
15693 if ( !panel.length ) {
15694 panel = that._createPanel( panelId );
15695 panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
15697 panel.attr( "aria-live", "polite" );
15700 if ( panel.length) {
15701 that.panels = that.panels.add( panel );
15703 if ( originalAriaControls ) {
15704 tab.data( "ui-tabs-aria-controls", originalAriaControls );
15707 "aria-controls": panelId,
15708 "aria-labelledby": anchorId
15710 panel.attr( "aria-labelledby", anchorId );
15714 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
15715 .attr( "role", "tabpanel" );
15717 // Avoid memory leaks (#10056)
15719 this._off( prevTabs.not( this.tabs ) );
15720 this._off( prevAnchors.not( this.anchors ) );
15721 this._off( prevPanels.not( this.panels ) );
15725 // allow overriding how to find the list for rare usage scenarios (#7715)
15726 _getList: function() {
15727 return this.tablist || this.element.find( "ol,ul" ).eq( 0 );
15730 _createPanel: function( id ) {
15731 return $( "<div>" )
15733 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
15734 .data( "ui-tabs-destroy", true );
15737 _setupDisabled: function( disabled ) {
15738 if ( $.isArray( disabled ) ) {
15739 if ( !disabled.length ) {
15741 } else if ( disabled.length === this.anchors.length ) {
15747 for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) {
15748 if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
15750 .addClass( "ui-state-disabled" )
15751 .attr( "aria-disabled", "true" );
15754 .removeClass( "ui-state-disabled" )
15755 .removeAttr( "aria-disabled" );
15759 this.options.disabled = disabled;
15762 _setupEvents: function( event ) {
15765 $.each( event.split(" "), function( index, eventName ) {
15766 events[ eventName ] = "_eventHandler";
15770 this._off( this.anchors.add( this.tabs ).add( this.panels ) );
15771 // Always prevent the default action, even when disabled
15772 this._on( true, this.anchors, {
15773 click: function( event ) {
15774 event.preventDefault();
15777 this._on( this.anchors, events );
15778 this._on( this.tabs, { keydown: "_tabKeydown" } );
15779 this._on( this.panels, { keydown: "_panelKeydown" } );
15781 this._focusable( this.tabs );
15782 this._hoverable( this.tabs );
15785 _setupHeightStyle: function( heightStyle ) {
15787 parent = this.element.parent();
15789 if ( heightStyle === "fill" ) {
15790 maxHeight = parent.height();
15791 maxHeight -= this.element.outerHeight() - this.element.height();
15793 this.element.siblings( ":visible" ).each(function() {
15794 var elem = $( this ),
15795 position = elem.css( "position" );
15797 if ( position === "absolute" || position === "fixed" ) {
15800 maxHeight -= elem.outerHeight( true );
15803 this.element.children().not( this.panels ).each(function() {
15804 maxHeight -= $( this ).outerHeight( true );
15807 this.panels.each(function() {
15808 $( this ).height( Math.max( 0, maxHeight -
15809 $( this ).innerHeight() + $( this ).height() ) );
15811 .css( "overflow", "auto" );
15812 } else if ( heightStyle === "auto" ) {
15814 this.panels.each(function() {
15815 maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
15816 }).height( maxHeight );
15820 _eventHandler: function( event ) {
15821 var options = this.options,
15822 active = this.active,
15823 anchor = $( event.currentTarget ),
15824 tab = anchor.closest( "li" ),
15825 clickedIsActive = tab[ 0 ] === active[ 0 ],
15826 collapsing = clickedIsActive && options.collapsible,
15827 toShow = collapsing ? $() : this._getPanelForTab( tab ),
15828 toHide = !active.length ? $() : this._getPanelForTab( active ),
15832 newTab: collapsing ? $() : tab,
15836 event.preventDefault();
15838 if ( tab.hasClass( "ui-state-disabled" ) ||
15839 // tab is already loading
15840 tab.hasClass( "ui-tabs-loading" ) ||
15841 // can't switch durning an animation
15843 // click on active header, but not collapsible
15844 ( clickedIsActive && !options.collapsible ) ||
15845 // allow canceling activation
15846 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
15850 options.active = collapsing ? false : this.tabs.index( tab );
15852 this.active = clickedIsActive ? $() : tab;
15857 if ( !toHide.length && !toShow.length ) {
15858 $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
15861 if ( toShow.length ) {
15862 this.load( this.tabs.index( tab ), event );
15864 this._toggle( event, eventData );
15867 // handles show/hide for selecting tabs
15868 _toggle: function( event, eventData ) {
15870 toShow = eventData.newPanel,
15871 toHide = eventData.oldPanel;
15873 this.running = true;
15875 function complete() {
15876 that.running = false;
15877 that._trigger( "activate", event, eventData );
15881 eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" );
15883 if ( toShow.length && that.options.show ) {
15884 that._show( toShow, that.options.show, complete );
15891 // start out by hiding, then showing, then completing
15892 if ( toHide.length && this.options.hide ) {
15893 this._hide( toHide, this.options.hide, function() {
15894 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
15898 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
15903 toHide.attr( "aria-hidden", "true" );
15904 eventData.oldTab.attr({
15905 "aria-selected": "false",
15906 "aria-expanded": "false"
15908 // If we're switching tabs, remove the old tab from the tab order.
15909 // If we're opening from collapsed state, remove the previous tab from the tab order.
15910 // If we're collapsing, then keep the collapsing tab in the tab order.
15911 if ( toShow.length && toHide.length ) {
15912 eventData.oldTab.attr( "tabIndex", -1 );
15913 } else if ( toShow.length ) {
15914 this.tabs.filter(function() {
15915 return $( this ).attr( "tabIndex" ) === 0;
15917 .attr( "tabIndex", -1 );
15920 toShow.attr( "aria-hidden", "false" );
15921 eventData.newTab.attr({
15922 "aria-selected": "true",
15923 "aria-expanded": "true",
15928 _activate: function( index ) {
15930 active = this._findActive( index );
15932 // trying to activate the already active panel
15933 if ( active[ 0 ] === this.active[ 0 ] ) {
15937 // trying to collapse, simulate a click on the current active header
15938 if ( !active.length ) {
15939 active = this.active;
15942 anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
15943 this._eventHandler({
15945 currentTarget: anchor,
15946 preventDefault: $.noop
15950 _findActive: function( index ) {
15951 return index === false ? $() : this.tabs.eq( index );
15954 _getIndex: function( index ) {
15955 // meta-function to give users option to provide a href string instead of a numerical index.
15956 if ( typeof index === "string" ) {
15957 index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) );
15963 _destroy: function() {
15968 this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" );
15971 .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
15972 .removeAttr( "role" );
15975 .removeClass( "ui-tabs-anchor" )
15976 .removeAttr( "role" )
15977 .removeAttr( "tabIndex" )
15980 this.tablist.unbind( this.eventNamespace );
15982 this.tabs.add( this.panels ).each(function() {
15983 if ( $.data( this, "ui-tabs-destroy" ) ) {
15984 $( this ).remove();
15987 .removeClass( "ui-state-default ui-state-active ui-state-disabled " +
15988 "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" )
15989 .removeAttr( "tabIndex" )
15990 .removeAttr( "aria-live" )
15991 .removeAttr( "aria-busy" )
15992 .removeAttr( "aria-selected" )
15993 .removeAttr( "aria-labelledby" )
15994 .removeAttr( "aria-hidden" )
15995 .removeAttr( "aria-expanded" )
15996 .removeAttr( "role" );
16000 this.tabs.each(function() {
16001 var li = $( this ),
16002 prev = li.data( "ui-tabs-aria-controls" );
16005 .attr( "aria-controls", prev )
16006 .removeData( "ui-tabs-aria-controls" );
16008 li.removeAttr( "aria-controls" );
16012 this.panels.show();
16014 if ( this.options.heightStyle !== "content" ) {
16015 this.panels.css( "height", "" );
16019 enable: function( index ) {
16020 var disabled = this.options.disabled;
16021 if ( disabled === false ) {
16025 if ( index === undefined ) {
16028 index = this._getIndex( index );
16029 if ( $.isArray( disabled ) ) {
16030 disabled = $.map( disabled, function( num ) {
16031 return num !== index ? num : null;
16034 disabled = $.map( this.tabs, function( li, num ) {
16035 return num !== index ? num : null;
16039 this._setupDisabled( disabled );
16042 disable: function( index ) {
16043 var disabled = this.options.disabled;
16044 if ( disabled === true ) {
16048 if ( index === undefined ) {
16051 index = this._getIndex( index );
16052 if ( $.inArray( index, disabled ) !== -1 ) {
16055 if ( $.isArray( disabled ) ) {
16056 disabled = $.merge( [ index ], disabled ).sort();
16058 disabled = [ index ];
16061 this._setupDisabled( disabled );
16064 load: function( index, event ) {
16065 index = this._getIndex( index );
16067 tab = this.tabs.eq( index ),
16068 anchor = tab.find( ".ui-tabs-anchor" ),
16069 panel = this._getPanelForTab( tab ),
16076 if ( this._isLocal( anchor[ 0 ] ) ) {
16080 this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
16082 // support: jQuery <1.8
16083 // jQuery <1.8 returns false if the request is canceled in beforeSend,
16084 // but as of 1.8, $.ajax() always returns a jqXHR object.
16085 if ( this.xhr && this.xhr.statusText !== "canceled" ) {
16086 tab.addClass( "ui-tabs-loading" );
16087 panel.attr( "aria-busy", "true" );
16090 .success(function( response ) {
16091 // support: jQuery <1.8
16092 // http://bugs.jquery.com/ticket/11778
16093 setTimeout(function() {
16094 panel.html( response );
16095 that._trigger( "load", event, eventData );
16098 .complete(function( jqXHR, status ) {
16099 // support: jQuery <1.8
16100 // http://bugs.jquery.com/ticket/11778
16101 setTimeout(function() {
16102 if ( status === "abort" ) {
16103 that.panels.stop( false, true );
16106 tab.removeClass( "ui-tabs-loading" );
16107 panel.removeAttr( "aria-busy" );
16109 if ( jqXHR === that.xhr ) {
16117 _ajaxSettings: function( anchor, event, eventData ) {
16120 url: anchor.attr( "href" ),
16121 beforeSend: function( jqXHR, settings ) {
16122 return that._trigger( "beforeLoad", event,
16123 $.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) );
16128 _getPanelForTab: function( tab ) {
16129 var id = $( tab ).attr( "aria-controls" );
16130 return this.element.find( this._sanitizeSelector( "#" + id ) );
16136 * jQuery UI Tooltip 1.11.2
16137 * http://jqueryui.com
16139 * Copyright 2014 jQuery Foundation and other contributors
16140 * Released under the MIT license.
16141 * http://jquery.org/license
16143 * http://api.jqueryui.com/tooltip/
16147 var tooltip = $.widget( "ui.tooltip", {
16150 content: function() {
16151 // support: IE<9, Opera in jQuery <1.7
16152 // .text() can't accept undefined, so coerce to a string
16153 var title = $( this ).attr( "title" ) || "";
16154 // Escape title, since we're going from an attribute to raw HTML
16155 return $( "<a>" ).text( title ).html();
16158 // Disabled elements have inconsistent behavior across browsers (#8661)
16159 items: "[title]:not([disabled])",
16163 collision: "flipfit flip"
16166 tooltipClass: null,
16174 _addDescribedBy: function( elem, id ) {
16175 var describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ );
16176 describedby.push( id );
16178 .data( "ui-tooltip-id", id )
16179 .attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
16182 _removeDescribedBy: function( elem ) {
16183 var id = elem.data( "ui-tooltip-id" ),
16184 describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ),
16185 index = $.inArray( id, describedby );
16187 if ( index !== -1 ) {
16188 describedby.splice( index, 1 );
16191 elem.removeData( "ui-tooltip-id" );
16192 describedby = $.trim( describedby.join( " " ) );
16193 if ( describedby ) {
16194 elem.attr( "aria-describedby", describedby );
16196 elem.removeAttr( "aria-describedby" );
16200 _create: function() {
16206 // IDs of generated tooltips, needed for destroy
16207 this.tooltips = {};
16209 // IDs of parent tooltips where we removed the title attribute
16212 if ( this.options.disabled ) {
16216 // Append the aria-live region so tooltips announce correctly
16217 this.liveRegion = $( "<div>" )
16220 "aria-live": "assertive",
16221 "aria-relevant": "additions"
16223 .addClass( "ui-helper-hidden-accessible" )
16224 .appendTo( this.document[ 0 ].body );
16227 _setOption: function( key, value ) {
16230 if ( key === "disabled" ) {
16231 this[ value ? "_disable" : "_enable" ]();
16232 this.options[ key ] = value;
16233 // disable element style changes
16237 this._super( key, value );
16239 if ( key === "content" ) {
16240 $.each( this.tooltips, function( id, tooltipData ) {
16241 that._updateContent( tooltipData.element );
16246 _disable: function() {
16249 // close open tooltips
16250 $.each( this.tooltips, function( id, tooltipData ) {
16251 var event = $.Event( "blur" );
16252 event.target = event.currentTarget = tooltipData.element[ 0 ];
16253 that.close( event, true );
16256 // remove title attributes to prevent native tooltips
16257 this.element.find( this.options.items ).addBack().each(function() {
16258 var element = $( this );
16259 if ( element.is( "[title]" ) ) {
16261 .data( "ui-tooltip-title", element.attr( "title" ) )
16262 .removeAttr( "title" );
16267 _enable: function() {
16268 // restore title attributes
16269 this.element.find( this.options.items ).addBack().each(function() {
16270 var element = $( this );
16271 if ( element.data( "ui-tooltip-title" ) ) {
16272 element.attr( "title", element.data( "ui-tooltip-title" ) );
16277 open: function( event ) {
16279 target = $( event ? event.target : this.element )
16280 // we need closest here due to mouseover bubbling,
16281 // but always pointing at the same event target
16282 .closest( this.options.items );
16284 // No element to show a tooltip for or the tooltip is already open
16285 if ( !target.length || target.data( "ui-tooltip-id" ) ) {
16289 if ( target.attr( "title" ) ) {
16290 target.data( "ui-tooltip-title", target.attr( "title" ) );
16293 target.data( "ui-tooltip-open", true );
16295 // kill parent tooltips, custom or native, for hover
16296 if ( event && event.type === "mouseover" ) {
16297 target.parents().each(function() {
16298 var parent = $( this ),
16300 if ( parent.data( "ui-tooltip-open" ) ) {
16301 blurEvent = $.Event( "blur" );
16302 blurEvent.target = blurEvent.currentTarget = this;
16303 that.close( blurEvent, true );
16305 if ( parent.attr( "title" ) ) {
16307 that.parents[ this.id ] = {
16309 title: parent.attr( "title" )
16311 parent.attr( "title", "" );
16316 this._updateContent( target, event );
16319 _updateContent: function( target, event ) {
16321 contentOption = this.options.content,
16323 eventType = event ? event.type : null;
16325 if ( typeof contentOption === "string" ) {
16326 return this._open( event, target, contentOption );
16329 content = contentOption.call( target[0], function( response ) {
16330 // ignore async response if tooltip was closed already
16331 if ( !target.data( "ui-tooltip-open" ) ) {
16334 // IE may instantly serve a cached response for ajax requests
16335 // delay this call to _open so the other call to _open runs first
16336 that._delay(function() {
16337 // jQuery creates a special event for focusin when it doesn't
16338 // exist natively. To improve performance, the native event
16339 // object is reused and the type is changed. Therefore, we can't
16340 // rely on the type being correct after the event finished
16341 // bubbling, so we set it back to the previous value. (#8740)
16343 event.type = eventType;
16345 this._open( event, target, response );
16349 this._open( event, target, content );
16353 _open: function( event, target, content ) {
16354 var tooltipData, tooltip, events, delayedShow, a11yContent,
16355 positionOption = $.extend( {}, this.options.position );
16361 // Content can be updated multiple times. If the tooltip already
16362 // exists, then just update the content and bail.
16363 tooltipData = this._find( target );
16364 if ( tooltipData ) {
16365 tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content );
16369 // if we have a title, clear it to prevent the native tooltip
16370 // we have to check first to avoid defining a title if none exists
16371 // (we don't want to cause an element to start matching [title])
16373 // We use removeAttr only for key events, to allow IE to export the correct
16374 // accessible attributes. For mouse events, set to empty string to avoid
16375 // native tooltip showing up (happens only when removing inside mouseover).
16376 if ( target.is( "[title]" ) ) {
16377 if ( event && event.type === "mouseover" ) {
16378 target.attr( "title", "" );
16380 target.removeAttr( "title" );
16384 tooltipData = this._tooltip( target );
16385 tooltip = tooltipData.tooltip;
16386 this._addDescribedBy( target, tooltip.attr( "id" ) );
16387 tooltip.find( ".ui-tooltip-content" ).html( content );
16389 // Support: Voiceover on OS X, JAWS on IE <= 9
16390 // JAWS announces deletions even when aria-relevant="additions"
16391 // Voiceover will sometimes re-read the entire log region's contents from the beginning
16392 this.liveRegion.children().hide();
16393 if ( content.clone ) {
16394 a11yContent = content.clone();
16395 a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" );
16397 a11yContent = content;
16399 $( "<div>" ).html( a11yContent ).appendTo( this.liveRegion );
16401 function position( event ) {
16402 positionOption.of = event;
16403 if ( tooltip.is( ":hidden" ) ) {
16406 tooltip.position( positionOption );
16408 if ( this.options.track && event && /^mouse/.test( event.type ) ) {
16409 this._on( this.document, {
16410 mousemove: position
16412 // trigger once to override element-relative positioning
16415 tooltip.position( $.extend({
16417 }, this.options.position ) );
16422 this._show( tooltip, this.options.show );
16423 // Handle tracking tooltips that are shown with a delay (#8644). As soon
16424 // as the tooltip is visible, position the tooltip using the most recent
16426 if ( this.options.show && this.options.show.delay ) {
16427 delayedShow = this.delayedShow = setInterval(function() {
16428 if ( tooltip.is( ":visible" ) ) {
16429 position( positionOption.of );
16430 clearInterval( delayedShow );
16432 }, $.fx.interval );
16435 this._trigger( "open", event, { tooltip: tooltip } );
16438 keyup: function( event ) {
16439 if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
16440 var fakeEvent = $.Event(event);
16441 fakeEvent.currentTarget = target[0];
16442 this.close( fakeEvent, true );
16447 // Only bind remove handler for delegated targets. Non-delegated
16448 // tooltips will handle this in destroy.
16449 if ( target[ 0 ] !== this.element[ 0 ] ) {
16450 events.remove = function() {
16451 this._removeTooltip( tooltip );
16455 if ( !event || event.type === "mouseover" ) {
16456 events.mouseleave = "close";
16458 if ( !event || event.type === "focusin" ) {
16459 events.focusout = "close";
16461 this._on( true, target, events );
16464 close: function( event ) {
16467 target = $( event ? event.currentTarget : this.element ),
16468 tooltipData = this._find( target );
16470 // The tooltip may already be closed
16471 if ( !tooltipData ) {
16475 tooltip = tooltipData.tooltip;
16477 // disabling closes the tooltip, so we need to track when we're closing
16478 // to avoid an infinite loop in case the tooltip becomes disabled on close
16479 if ( tooltipData.closing ) {
16483 // Clear the interval for delayed tracking tooltips
16484 clearInterval( this.delayedShow );
16486 // only set title if we had one before (see comment in _open())
16487 // If the title attribute has changed since open(), don't restore
16488 if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) {
16489 target.attr( "title", target.data( "ui-tooltip-title" ) );
16492 this._removeDescribedBy( target );
16494 tooltipData.hiding = true;
16495 tooltip.stop( true );
16496 this._hide( tooltip, this.options.hide, function() {
16497 that._removeTooltip( $( this ) );
16500 target.removeData( "ui-tooltip-open" );
16501 this._off( target, "mouseleave focusout keyup" );
16503 // Remove 'remove' binding only on delegated targets
16504 if ( target[ 0 ] !== this.element[ 0 ] ) {
16505 this._off( target, "remove" );
16507 this._off( this.document, "mousemove" );
16509 if ( event && event.type === "mouseleave" ) {
16510 $.each( this.parents, function( id, parent ) {
16511 $( parent.element ).attr( "title", parent.title );
16512 delete that.parents[ id ];
16516 tooltipData.closing = true;
16517 this._trigger( "close", event, { tooltip: tooltip } );
16518 if ( !tooltipData.hiding ) {
16519 tooltipData.closing = false;
16523 _tooltip: function( element ) {
16524 var tooltip = $( "<div>" )
16525 .attr( "role", "tooltip" )
16526 .addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " +
16527 ( this.options.tooltipClass || "" ) ),
16528 id = tooltip.uniqueId().attr( "id" );
16531 .addClass( "ui-tooltip-content" )
16532 .appendTo( tooltip );
16534 tooltip.appendTo( this.document[0].body );
16536 return this.tooltips[ id ] = {
16542 _find: function( target ) {
16543 var id = target.data( "ui-tooltip-id" );
16544 return id ? this.tooltips[ id ] : null;
16547 _removeTooltip: function( tooltip ) {
16549 delete this.tooltips[ tooltip.attr( "id" ) ];
16552 _destroy: function() {
16555 // close open tooltips
16556 $.each( this.tooltips, function( id, tooltipData ) {
16557 // Delegate to close method to handle common cleanup
16558 var event = $.Event( "blur" ),
16559 element = tooltipData.element;
16560 event.target = event.currentTarget = element[ 0 ];
16561 that.close( event, true );
16563 // Remove immediately; destroying an open tooltip doesn't use the
16565 $( "#" + id ).remove();
16567 // Restore the title
16568 if ( element.data( "ui-tooltip-title" ) ) {
16569 // If the title attribute has changed since open(), don't restore
16570 if ( !element.attr( "title" ) ) {
16571 element.attr( "title", element.data( "ui-tooltip-title" ) );
16573 element.removeData( "ui-tooltip-title" );
16576 this.liveRegion.remove();