1 /*! jQuery UI - v1.10.3 - 2013-05-03
3 * Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.draggable.js, jquery.ui.droppable.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.sortable.js, jquery.ui.effect.js, jquery.ui.accordion.js, jquery.ui.autocomplete.js, jquery.ui.button.js, jquery.ui.datepicker.js, jquery.ui.dialog.js, jquery.ui.effect-blind.js, jquery.ui.effect-bounce.js, jquery.ui.effect-clip.js, jquery.ui.effect-drop.js, jquery.ui.effect-explode.js, jquery.ui.effect-fade.js, jquery.ui.effect-fold.js, jquery.ui.effect-highlight.js, jquery.ui.effect-pulsate.js, jquery.ui.effect-scale.js, jquery.ui.effect-shake.js, jquery.ui.effect-slide.js, jquery.ui.effect-transfer.js, jquery.ui.menu.js, jquery.ui.position.js, jquery.ui.progressbar.js, jquery.ui.slider.js, jquery.ui.spinner.js, jquery.ui.tabs.js, jquery.ui.tooltip.js
4 * Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
5 (function( $, undefined ) {
8 runiqueId = /^ui-id-\d+$/;
10 // $.ui might exist from components with no dependencies, e.g., $.ui.position
44 focus: (function( orig ) {
45 return function( delay, fn ) {
46 return typeof delay === "number" ?
47 this.each(function() {
49 setTimeout(function() {
56 orig.apply( this, arguments );
60 scrollParent: function() {
62 if (($.ui.ie && (/(static|relative)/).test(this.css("position"))) || (/absolute/).test(this.css("position"))) {
63 scrollParent = this.parents().filter(function() {
64 return (/(relative|absolute|fixed)/).test($.css(this,"position")) && (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x"));
67 scrollParent = this.parents().filter(function() {
68 return (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x"));
72 return (/fixed/).test(this.css("position")) || !scrollParent.length ? $(document) : scrollParent;
75 zIndex: function( zIndex ) {
76 if ( zIndex !== undefined ) {
77 return this.css( "zIndex", zIndex );
81 var elem = $( this[ 0 ] ), position, value;
82 while ( elem.length && elem[ 0 ] !== document ) {
83 // Ignore z-index if position is set to a value where z-index is ignored by the browser
84 // This makes behavior of this function consistent across browsers
85 // WebKit always returns auto if the element is positioned
86 position = elem.css( "position" );
87 if ( position === "absolute" || position === "relative" || position === "fixed" ) {
88 // IE returns 0 when zIndex is not specified
89 // other browsers return a string
90 // we ignore the case of nested elements with an explicit value of 0
91 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
92 value = parseInt( elem.css( "zIndex" ), 10 );
93 if ( !isNaN( value ) && value !== 0 ) {
104 uniqueId: function() {
105 return this.each(function() {
107 this.id = "ui-id-" + (++uuid);
112 removeUniqueId: function() {
113 return this.each(function() {
114 if ( runiqueId.test( this.id ) ) {
115 $( this ).removeAttr( "id" );
122 function focusable( element, isTabIndexNotNaN ) {
123 var map, mapName, img,
124 nodeName = element.nodeName.toLowerCase();
125 if ( "area" === nodeName ) {
126 map = element.parentNode;
128 if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
131 img = $( "img[usemap=#" + mapName + "]" )[0];
132 return !!img && visible( img );
134 return ( /input|select|textarea|button|object/.test( nodeName ) ?
137 element.href || isTabIndexNotNaN :
139 // the element and all of its ancestors must be visible
143 function visible( element ) {
144 return $.expr.filters.visible( element ) &&
145 !$( element ).parents().addBack().filter(function() {
146 return $.css( this, "visibility" ) === "hidden";
150 $.extend( $.expr[ ":" ], {
151 data: $.expr.createPseudo ?
152 $.expr.createPseudo(function( dataName ) {
153 return function( elem ) {
154 return !!$.data( elem, dataName );
157 // support: jQuery <1.8
158 function( elem, i, match ) {
159 return !!$.data( elem, match[ 3 ] );
162 focusable: function( element ) {
163 return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) );
166 tabbable: function( element ) {
167 var tabIndex = $.attr( element, "tabindex" ),
168 isTabIndexNaN = isNaN( tabIndex );
169 return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN );
173 // support: jQuery <1.8
174 if ( !$( "<a>" ).outerWidth( 1 ).jquery ) {
175 $.each( [ "Width", "Height" ], function( i, name ) {
176 var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
177 type = name.toLowerCase(),
179 innerWidth: $.fn.innerWidth,
180 innerHeight: $.fn.innerHeight,
181 outerWidth: $.fn.outerWidth,
182 outerHeight: $.fn.outerHeight
185 function reduce( elem, size, border, margin ) {
186 $.each( side, function() {
187 size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
189 size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
192 size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
198 $.fn[ "inner" + name ] = function( size ) {
199 if ( size === undefined ) {
200 return orig[ "inner" + name ].call( this );
203 return this.each(function() {
204 $( this ).css( type, reduce( this, size ) + "px" );
208 $.fn[ "outer" + name] = function( size, margin ) {
209 if ( typeof size !== "number" ) {
210 return orig[ "outer" + name ].call( this, size );
213 return this.each(function() {
214 $( this).css( type, reduce( this, size, true, margin ) + "px" );
220 // support: jQuery <1.8
221 if ( !$.fn.addBack ) {
222 $.fn.addBack = function( selector ) {
223 return this.add( selector == null ?
224 this.prevObject : this.prevObject.filter( selector )
229 // support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413)
230 if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) {
231 $.fn.removeData = (function( removeData ) {
232 return function( key ) {
233 if ( arguments.length ) {
234 return removeData.call( this, $.camelCase( key ) );
236 return removeData.call( this );
239 })( $.fn.removeData );
247 $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
249 $.support.selectstart = "onselectstart" in document.createElement( "div" );
251 disableSelection: function() {
252 return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) +
253 ".ui-disableSelection", function( event ) {
254 event.preventDefault();
258 enableSelection: function() {
259 return this.unbind( ".ui-disableSelection" );
264 // $.ui.plugin is deprecated. Use $.widget() extensions instead.
266 add: function( module, option, set ) {
268 proto = $.ui[ module ].prototype;
270 proto.plugins[ i ] = proto.plugins[ i ] || [];
271 proto.plugins[ i ].push( [ option, set[ i ] ] );
274 call: function( instance, name, args ) {
276 set = instance.plugins[ name ];
277 if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) {
281 for ( i = 0; i < set.length; i++ ) {
282 if ( instance.options[ set[ i ][ 0 ] ] ) {
283 set[ i ][ 1 ].apply( instance.element, args );
289 // only used by resizable
290 hasScroll: function( el, a ) {
292 //If overflow is hidden, the element might have extra content, but the user wants to hide it
293 if ( $( el ).css( "overflow" ) === "hidden") {
297 var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
300 if ( el[ scroll ] > 0 ) {
304 // TODO: determine which cases actually cause this to happen
305 // if the element doesn't have the scroll set, see if it's possible to
308 has = ( el[ scroll ] > 0 );
316 (function( $, undefined ) {
319 slice = Array.prototype.slice,
320 _cleanData = $.cleanData;
321 $.cleanData = function( elems ) {
322 for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
324 $( elem ).triggerHandler( "remove" );
325 // http://bugs.jquery.com/ticket/8235
331 $.widget = function( name, base, prototype ) {
332 var fullName, existingConstructor, constructor, basePrototype,
333 // proxiedPrototype allows the provided prototype to remain unmodified
334 // so that it can be used as a mixin for multiple widgets (#8876)
335 proxiedPrototype = {},
336 namespace = name.split( "." )[ 0 ];
338 name = name.split( "." )[ 1 ];
339 fullName = namespace + "-" + name;
346 // create selector for plugin
347 $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
348 return !!$.data( elem, fullName );
351 $[ namespace ] = $[ namespace ] || {};
352 existingConstructor = $[ namespace ][ name ];
353 constructor = $[ namespace ][ name ] = function( options, element ) {
354 // allow instantiation without "new" keyword
355 if ( !this._createWidget ) {
356 return new constructor( options, element );
359 // allow instantiation without initializing for simple inheritance
360 // must use "new" keyword (the code above always passes args)
361 if ( arguments.length ) {
362 this._createWidget( options, element );
365 // extend with the existing constructor to carry over any static properties
366 $.extend( constructor, existingConstructor, {
367 version: prototype.version,
368 // copy the object used to create the prototype in case we need to
369 // redefine the widget later
370 _proto: $.extend( {}, prototype ),
371 // track widgets that inherit from this widget in case this widget is
372 // redefined after a widget inherits from it
373 _childConstructors: []
376 basePrototype = new base();
377 // we need to make the options hash a property directly on the new instance
378 // otherwise we'll modify the options hash on the prototype that we're
380 basePrototype.options = $.widget.extend( {}, basePrototype.options );
381 $.each( prototype, function( prop, value ) {
382 if ( !$.isFunction( value ) ) {
383 proxiedPrototype[ prop ] = value;
386 proxiedPrototype[ prop ] = (function() {
387 var _super = function() {
388 return base.prototype[ prop ].apply( this, arguments );
390 _superApply = function( args ) {
391 return base.prototype[ prop ].apply( this, args );
394 var __super = this._super,
395 __superApply = this._superApply,
398 this._super = _super;
399 this._superApply = _superApply;
401 returnValue = value.apply( this, arguments );
403 this._super = __super;
404 this._superApply = __superApply;
410 constructor.prototype = $.widget.extend( basePrototype, {
411 // TODO: remove support for widgetEventPrefix
412 // always use the name + a colon as the prefix, e.g., draggable:start
413 // don't prefix for widgets that aren't DOM-based
414 widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name
415 }, proxiedPrototype, {
416 constructor: constructor,
417 namespace: namespace,
419 widgetFullName: fullName
422 // If this widget is being redefined then we need to find all widgets that
423 // are inheriting from it and redefine all of them so that they inherit from
424 // the new version of this widget. We're essentially trying to replace one
425 // level in the prototype chain.
426 if ( existingConstructor ) {
427 $.each( existingConstructor._childConstructors, function( i, child ) {
428 var childPrototype = child.prototype;
430 // redefine the child widget using the same prototype that was
431 // originally used, but inherit from the new version of the base
432 $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
434 // remove the list of existing child constructors from the old constructor
435 // so the old child constructors can be garbage collected
436 delete existingConstructor._childConstructors;
438 base._childConstructors.push( constructor );
441 $.widget.bridge( name, constructor );
444 $.widget.extend = function( target ) {
445 var input = slice.call( arguments, 1 ),
447 inputLength = input.length,
450 for ( ; inputIndex < inputLength; inputIndex++ ) {
451 for ( key in input[ inputIndex ] ) {
452 value = input[ inputIndex ][ key ];
453 if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
455 if ( $.isPlainObject( value ) ) {
456 target[ key ] = $.isPlainObject( target[ key ] ) ?
457 $.widget.extend( {}, target[ key ], value ) :
458 // Don't extend strings, arrays, etc. with objects
459 $.widget.extend( {}, value );
460 // Copy everything else by reference
462 target[ key ] = value;
470 $.widget.bridge = function( name, object ) {
471 var fullName = object.prototype.widgetFullName || name;
472 $.fn[ name ] = function( options ) {
473 var isMethodCall = typeof options === "string",
474 args = slice.call( arguments, 1 ),
477 // allow multiple hashes to be passed on init
478 options = !isMethodCall && args.length ?
479 $.widget.extend.apply( null, [ options ].concat(args) ) :
482 if ( isMethodCall ) {
483 this.each(function() {
485 instance = $.data( this, fullName );
487 return $.error( "cannot call methods on " + name + " prior to initialization; " +
488 "attempted to call method '" + options + "'" );
490 if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
491 return $.error( "no such method '" + options + "' for " + name + " widget instance" );
493 methodValue = instance[ options ].apply( instance, args );
494 if ( methodValue !== instance && methodValue !== undefined ) {
495 returnValue = methodValue && methodValue.jquery ?
496 returnValue.pushStack( methodValue.get() ) :
502 this.each(function() {
503 var instance = $.data( this, fullName );
505 instance.option( options || {} )._init();
507 $.data( this, fullName, new object( options, this ) );
516 $.Widget = function( /* options, element */ ) {};
517 $.Widget._childConstructors = [];
519 $.Widget.prototype = {
520 widgetName: "widget",
521 widgetEventPrefix: "",
522 defaultElement: "<div>",
529 _createWidget: function( options, element ) {
530 element = $( element || this.defaultElement || this )[ 0 ];
531 this.element = $( element );
533 this.eventNamespace = "." + this.widgetName + this.uuid;
534 this.options = $.widget.extend( {},
536 this._getCreateOptions(),
540 this.hoverable = $();
541 this.focusable = $();
543 if ( element !== this ) {
544 $.data( element, this.widgetFullName, this );
545 this._on( true, this.element, {
546 remove: function( event ) {
547 if ( event.target === element ) {
552 this.document = $( element.style ?
553 // element within the document
554 element.ownerDocument :
555 // element is window or document
556 element.document || element );
557 this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
561 this._trigger( "create", null, this._getCreateEventData() );
564 _getCreateOptions: $.noop,
565 _getCreateEventData: $.noop,
569 destroy: function() {
571 // we can probably remove the unbind calls in 2.0
572 // all event bindings should go through this._on()
574 .unbind( this.eventNamespace )
576 // TODO remove dual storage
577 .removeData( this.widgetName )
578 .removeData( this.widgetFullName )
579 // support: jquery <1.6.3
580 // http://bugs.jquery.com/ticket/9413
581 .removeData( $.camelCase( this.widgetFullName ) );
583 .unbind( this.eventNamespace )
584 .removeAttr( "aria-disabled" )
586 this.widgetFullName + "-disabled " +
587 "ui-state-disabled" );
589 // clean up events and states
590 this.bindings.unbind( this.eventNamespace );
591 this.hoverable.removeClass( "ui-state-hover" );
592 this.focusable.removeClass( "ui-state-focus" );
600 option: function( key, value ) {
606 if ( arguments.length === 0 ) {
607 // don't return a reference to the internal hash
608 return $.widget.extend( {}, this.options );
611 if ( typeof key === "string" ) {
612 // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
614 parts = key.split( "." );
616 if ( parts.length ) {
617 curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
618 for ( i = 0; i < parts.length - 1; i++ ) {
619 curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
620 curOption = curOption[ parts[ i ] ];
623 if ( value === undefined ) {
624 return curOption[ key ] === undefined ? null : curOption[ key ];
626 curOption[ key ] = value;
628 if ( value === undefined ) {
629 return this.options[ key ] === undefined ? null : this.options[ key ];
631 options[ key ] = value;
635 this._setOptions( options );
639 _setOptions: function( options ) {
642 for ( key in options ) {
643 this._setOption( key, options[ key ] );
648 _setOption: function( key, value ) {
649 this.options[ key ] = value;
651 if ( key === "disabled" ) {
653 .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value )
654 .attr( "aria-disabled", value );
655 this.hoverable.removeClass( "ui-state-hover" );
656 this.focusable.removeClass( "ui-state-focus" );
663 return this._setOption( "disabled", false );
665 disable: function() {
666 return this._setOption( "disabled", true );
669 _on: function( suppressDisabledCheck, element, handlers ) {
673 // no suppressDisabledCheck flag, shuffle arguments
674 if ( typeof suppressDisabledCheck !== "boolean" ) {
676 element = suppressDisabledCheck;
677 suppressDisabledCheck = false;
680 // no element argument, shuffle and use this.element
683 element = this.element;
684 delegateElement = this.widget();
686 // accept selectors, DOM elements
687 element = delegateElement = $( element );
688 this.bindings = this.bindings.add( element );
691 $.each( handlers, function( event, handler ) {
692 function handlerProxy() {
693 // allow widgets to customize the disabled handling
694 // - disabled as an array instead of boolean
695 // - disabled class as method for disabling individual parts
696 if ( !suppressDisabledCheck &&
697 ( instance.options.disabled === true ||
698 $( this ).hasClass( "ui-state-disabled" ) ) ) {
701 return ( typeof handler === "string" ? instance[ handler ] : handler )
702 .apply( instance, arguments );
705 // copy the guid so direct unbinding works
706 if ( typeof handler !== "string" ) {
707 handlerProxy.guid = handler.guid =
708 handler.guid || handlerProxy.guid || $.guid++;
711 var match = event.match( /^(\w+)\s*(.*)$/ ),
712 eventName = match[1] + instance.eventNamespace,
715 delegateElement.delegate( selector, eventName, handlerProxy );
717 element.bind( eventName, handlerProxy );
722 _off: function( element, eventName ) {
723 eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace;
724 element.unbind( eventName ).undelegate( eventName );
727 _delay: function( handler, delay ) {
728 function handlerProxy() {
729 return ( typeof handler === "string" ? instance[ handler ] : handler )
730 .apply( instance, arguments );
733 return setTimeout( handlerProxy, delay || 0 );
736 _hoverable: function( element ) {
737 this.hoverable = this.hoverable.add( element );
739 mouseenter: function( event ) {
740 $( event.currentTarget ).addClass( "ui-state-hover" );
742 mouseleave: function( event ) {
743 $( event.currentTarget ).removeClass( "ui-state-hover" );
748 _focusable: function( element ) {
749 this.focusable = this.focusable.add( element );
751 focusin: function( event ) {
752 $( event.currentTarget ).addClass( "ui-state-focus" );
754 focusout: function( event ) {
755 $( event.currentTarget ).removeClass( "ui-state-focus" );
760 _trigger: function( type, event, data ) {
762 callback = this.options[ type ];
765 event = $.Event( event );
766 event.type = ( type === this.widgetEventPrefix ?
768 this.widgetEventPrefix + type ).toLowerCase();
769 // the original event may come from any element
770 // so we need to reset the target on the new event
771 event.target = this.element[ 0 ];
773 // copy original event properties over to the new event
774 orig = event.originalEvent;
776 for ( prop in orig ) {
777 if ( !( prop in event ) ) {
778 event[ prop ] = orig[ prop ];
783 this.element.trigger( event, data );
784 return !( $.isFunction( callback ) &&
785 callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
786 event.isDefaultPrevented() );
790 $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
791 $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
792 if ( typeof options === "string" ) {
793 options = { effect: options };
796 effectName = !options ?
798 options === true || typeof options === "number" ?
800 options.effect || defaultEffect;
801 options = options || {};
802 if ( typeof options === "number" ) {
803 options = { duration: options };
805 hasOptions = !$.isEmptyObject( options );
806 options.complete = callback;
807 if ( options.delay ) {
808 element.delay( options.delay );
810 if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
811 element[ method ]( options );
812 } else if ( effectName !== method && element[ effectName ] ) {
813 element[ effectName ]( options.duration, options.easing, callback );
815 element.queue(function( next ) {
816 $( this )[ method ]();
818 callback.call( element[ 0 ] );
828 (function( $, undefined ) {
830 var mouseHandled = false;
831 $( document ).mouseup( function() {
832 mouseHandled = false;
835 $.widget("ui.mouse", {
838 cancel: "input,textarea,button,select,option",
842 _mouseInit: function() {
846 .bind("mousedown."+this.widgetName, function(event) {
847 return that._mouseDown(event);
849 .bind("click."+this.widgetName, function(event) {
850 if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) {
851 $.removeData(event.target, that.widgetName + ".preventClickEvent");
852 event.stopImmediatePropagation();
857 this.started = false;
860 // TODO: make sure destroying one instance of mouse doesn't mess with
861 // other instances of mouse
862 _mouseDestroy: function() {
863 this.element.unbind("."+this.widgetName);
864 if ( this._mouseMoveDelegate ) {
866 .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate)
867 .unbind("mouseup."+this.widgetName, this._mouseUpDelegate);
871 _mouseDown: function(event) {
872 // don't let more than one widget handle mouseStart
873 if( mouseHandled ) { return; }
875 // we may have missed mouseup (out of window)
876 (this._mouseStarted && this._mouseUp(event));
878 this._mouseDownEvent = event;
881 btnIsLeft = (event.which === 1),
882 // event.target.nodeName works around a bug in IE 8 with
883 // disabled inputs (#7620)
884 elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false);
885 if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
889 this.mouseDelayMet = !this.options.delay;
890 if (!this.mouseDelayMet) {
891 this._mouseDelayTimer = setTimeout(function() {
892 that.mouseDelayMet = true;
893 }, this.options.delay);
896 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
897 this._mouseStarted = (this._mouseStart(event) !== false);
898 if (!this._mouseStarted) {
899 event.preventDefault();
904 // Click event may never have fired (Gecko & Opera)
905 if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) {
906 $.removeData(event.target, this.widgetName + ".preventClickEvent");
909 // these delegates are required to keep context
910 this._mouseMoveDelegate = function(event) {
911 return that._mouseMove(event);
913 this._mouseUpDelegate = function(event) {
914 return that._mouseUp(event);
917 .bind("mousemove."+this.widgetName, this._mouseMoveDelegate)
918 .bind("mouseup."+this.widgetName, this._mouseUpDelegate);
920 event.preventDefault();
926 _mouseMove: function(event) {
927 // IE mouseup check - mouseup happened when mouse was out of window
928 if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) {
929 return this._mouseUp(event);
932 if (this._mouseStarted) {
933 this._mouseDrag(event);
934 return event.preventDefault();
937 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
939 (this._mouseStart(this._mouseDownEvent, event) !== false);
940 (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
943 return !this._mouseStarted;
946 _mouseUp: function(event) {
948 .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate)
949 .unbind("mouseup."+this.widgetName, this._mouseUpDelegate);
951 if (this._mouseStarted) {
952 this._mouseStarted = false;
954 if (event.target === this._mouseDownEvent.target) {
955 $.data(event.target, this.widgetName + ".preventClickEvent", true);
958 this._mouseStop(event);
964 _mouseDistanceMet: function(event) {
966 Math.abs(this._mouseDownEvent.pageX - event.pageX),
967 Math.abs(this._mouseDownEvent.pageY - event.pageY)
968 ) >= this.options.distance
972 _mouseDelayMet: function(/* event */) {
973 return this.mouseDelayMet;
976 // These are placeholder methods, to be overriden by extending plugin
977 _mouseStart: function(/* event */) {},
978 _mouseDrag: function(/* event */) {},
979 _mouseStop: function(/* event */) {},
980 _mouseCapture: function(/* event */) { return true; }
985 (function( $, undefined ) {
987 $.widget("ui.draggable", $.ui.mouse, {
989 widgetEventPrefix: "drag",
994 connectToSortable: false,
1003 refreshPositions: false,
1005 revertDuration: 500,
1008 scrollSensitivity: 20,
1021 _create: function() {
1023 if (this.options.helper === "original" && !(/^(?:r|a|f)/).test(this.element.css("position"))) {
1024 this.element[0].style.position = "relative";
1026 if (this.options.addClasses){
1027 this.element.addClass("ui-draggable");
1029 if (this.options.disabled){
1030 this.element.addClass("ui-draggable-disabled");
1037 _destroy: function() {
1038 this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" );
1039 this._mouseDestroy();
1042 _mouseCapture: function(event) {
1044 var o = this.options;
1046 // among others, prevent a drag on a resizable-handle
1047 if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) {
1051 //Quit if we're not on a valid handle
1052 this.handle = this._getHandle(event);
1057 $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() {
1058 $("<div class='ui-draggable-iframeFix' style='background: #fff;'></div>")
1060 width: this.offsetWidth+"px", height: this.offsetHeight+"px",
1061 position: "absolute", opacity: "0.001", zIndex: 1000
1063 .css($(this).offset())
1071 _mouseStart: function(event) {
1073 var o = this.options;
1075 //Create and append the visible helper
1076 this.helper = this._createHelper(event);
1078 this.helper.addClass("ui-draggable-dragging");
1080 //Cache the helper size
1081 this._cacheHelperProportions();
1083 //If ddmanager is used for droppables, set the global draggable
1084 if($.ui.ddmanager) {
1085 $.ui.ddmanager.current = this;
1089 * - Position generation -
1090 * This block generates everything position related - it's the core of draggables.
1093 //Cache the margins of the original element
1094 this._cacheMargins();
1096 //Store the helper's css position
1097 this.cssPosition = this.helper.css( "position" );
1098 this.scrollParent = this.helper.scrollParent();
1099 this.offsetParent = this.helper.offsetParent();
1100 this.offsetParentCssPosition = this.offsetParent.css( "position" );
1102 //The element's absolute position on the page minus margins
1103 this.offset = this.positionAbs = this.element.offset();
1105 top: this.offset.top - this.margins.top,
1106 left: this.offset.left - this.margins.left
1109 //Reset scroll cache
1110 this.offset.scroll = false;
1112 $.extend(this.offset, {
1113 click: { //Where the click happened, relative to the element
1114 left: event.pageX - this.offset.left,
1115 top: event.pageY - this.offset.top
1117 parent: this._getParentOffset(),
1118 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
1121 //Generate the original position
1122 this.originalPosition = this.position = this._generatePosition(event);
1123 this.originalPageX = event.pageX;
1124 this.originalPageY = event.pageY;
1126 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
1127 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
1129 //Set a containment if given in the options
1130 this._setContainment();
1132 //Trigger event + callbacks
1133 if(this._trigger("start", event) === false) {
1138 //Recache the helper size
1139 this._cacheHelperProportions();
1141 //Prepare the droppable offsets
1142 if ($.ui.ddmanager && !o.dropBehaviour) {
1143 $.ui.ddmanager.prepareOffsets(this, event);
1147 this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
1149 //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
1150 if ( $.ui.ddmanager ) {
1151 $.ui.ddmanager.dragStart(this, event);
1157 _mouseDrag: function(event, noPropagation) {
1158 // reset any necessary cached properties (see #5009)
1159 if ( this.offsetParentCssPosition === "fixed" ) {
1160 this.offset.parent = this._getParentOffset();
1163 //Compute the helpers position
1164 this.position = this._generatePosition(event);
1165 this.positionAbs = this._convertPositionTo("absolute");
1167 //Call plugins and callbacks and use the resulting position if something is returned
1168 if (!noPropagation) {
1169 var ui = this._uiHash();
1170 if(this._trigger("drag", event, ui) === false) {
1174 this.position = ui.position;
1177 if(!this.options.axis || this.options.axis !== "y") {
1178 this.helper[0].style.left = this.position.left+"px";
1180 if(!this.options.axis || this.options.axis !== "x") {
1181 this.helper[0].style.top = this.position.top+"px";
1183 if($.ui.ddmanager) {
1184 $.ui.ddmanager.drag(this, event);
1190 _mouseStop: function(event) {
1192 //If we are using droppables, inform the manager about the drop
1195 if ($.ui.ddmanager && !this.options.dropBehaviour) {
1196 dropped = $.ui.ddmanager.drop(this, event);
1199 //if a drop comes from outside (a sortable)
1201 dropped = this.dropped;
1202 this.dropped = false;
1205 //if the original element is no longer in the DOM don't bother to continue (see #8269)
1206 if ( this.options.helper === "original" && !$.contains( this.element[ 0 ].ownerDocument, this.element[ 0 ] ) ) {
1210 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))) {
1211 $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
1212 if(that._trigger("stop", event) !== false) {
1217 if(this._trigger("stop", event) !== false) {
1225 _mouseUp: function(event) {
1226 //Remove frame helpers
1227 $("div.ui-draggable-iframeFix").each(function() {
1228 this.parentNode.removeChild(this);
1231 //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003)
1232 if( $.ui.ddmanager ) {
1233 $.ui.ddmanager.dragStop(this, event);
1236 return $.ui.mouse.prototype._mouseUp.call(this, event);
1239 cancel: function() {
1241 if(this.helper.is(".ui-draggable-dragging")) {
1251 _getHandle: function(event) {
1252 return this.options.handle ?
1253 !!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
1257 _createHelper: function(event) {
1259 var o = this.options,
1260 helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper === "clone" ? this.element.clone().removeAttr("id") : this.element);
1262 if(!helper.parents("body").length) {
1263 helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo));
1266 if(helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) {
1267 helper.css("position", "absolute");
1274 _adjustOffsetFromHelper: function(obj) {
1275 if (typeof obj === "string") {
1276 obj = obj.split(" ");
1278 if ($.isArray(obj)) {
1279 obj = {left: +obj[0], top: +obj[1] || 0};
1281 if ("left" in obj) {
1282 this.offset.click.left = obj.left + this.margins.left;
1284 if ("right" in obj) {
1285 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
1288 this.offset.click.top = obj.top + this.margins.top;
1290 if ("bottom" in obj) {
1291 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
1295 _getParentOffset: function() {
1297 //Get the offsetParent and cache its position
1298 var po = this.offsetParent.offset();
1300 // This is a special case where we need to modify a offset calculated on start, since the following happened:
1301 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
1302 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
1303 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
1304 if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
1305 po.left += this.scrollParent.scrollLeft();
1306 po.top += this.scrollParent.scrollTop();
1309 //This needs to be actually done for all browsers, since pageX/pageY includes this information
1311 if((this.offsetParent[0] === document.body) ||
1312 (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
1313 po = { top: 0, left: 0 };
1317 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
1318 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
1323 _getRelativeOffset: function() {
1325 if(this.cssPosition === "relative") {
1326 var p = this.element.position();
1328 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
1329 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
1332 return { top: 0, left: 0 };
1337 _cacheMargins: function() {
1339 left: (parseInt(this.element.css("marginLeft"),10) || 0),
1340 top: (parseInt(this.element.css("marginTop"),10) || 0),
1341 right: (parseInt(this.element.css("marginRight"),10) || 0),
1342 bottom: (parseInt(this.element.css("marginBottom"),10) || 0)
1346 _cacheHelperProportions: function() {
1347 this.helperProportions = {
1348 width: this.helper.outerWidth(),
1349 height: this.helper.outerHeight()
1353 _setContainment: function() {
1358 if ( !o.containment ) {
1359 this.containment = null;
1363 if ( o.containment === "window" ) {
1364 this.containment = [
1365 $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
1366 $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
1367 $( window ).scrollLeft() + $( window ).width() - this.helperProportions.width - this.margins.left,
1368 $( window ).scrollTop() + ( $( window ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
1373 if ( o.containment === "document") {
1374 this.containment = [
1377 $( document ).width() - this.helperProportions.width - this.margins.left,
1378 ( $( document ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
1383 if ( o.containment.constructor === Array ) {
1384 this.containment = o.containment;
1388 if ( o.containment === "parent" ) {
1389 o.containment = this.helper[ 0 ].parentNode;
1392 c = $( o.containment );
1399 over = c.css( "overflow" ) !== "hidden";
1401 this.containment = [
1402 ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
1403 ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ) ,
1404 ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) - ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) - this.helperProportions.width - this.margins.left - this.margins.right,
1405 ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) - ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) - this.helperProportions.height - this.margins.top - this.margins.bottom
1407 this.relative_container = c;
1410 _convertPositionTo: function(d, pos) {
1413 pos = this.position;
1416 var mod = d === "absolute" ? 1 : -1,
1417 scroll = this.cssPosition === "absolute" && !( this.scrollParent[ 0 ] !== document && $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? this.offsetParent : this.scrollParent;
1420 if (!this.offset.scroll) {
1421 this.offset.scroll = {top : scroll.scrollTop(), left : scroll.scrollLeft()};
1426 pos.top + // The absolute mouse position
1427 this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
1428 this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
1429 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : this.offset.scroll.top ) * mod )
1432 pos.left + // The absolute mouse position
1433 this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
1434 this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
1435 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : this.offset.scroll.left ) * mod )
1441 _generatePosition: function(event) {
1443 var containment, co, top, left,
1445 scroll = this.cssPosition === "absolute" && !( this.scrollParent[ 0 ] !== document && $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? this.offsetParent : this.scrollParent,
1446 pageX = event.pageX,
1447 pageY = event.pageY;
1450 if (!this.offset.scroll) {
1451 this.offset.scroll = {top : scroll.scrollTop(), left : scroll.scrollLeft()};
1455 * - Position constraining -
1456 * Constrain the position to a mix of grid, containment.
1459 // If we are not dragging yet, we won't check for options
1460 if ( this.originalPosition ) {
1461 if ( this.containment ) {
1462 if ( this.relative_container ){
1463 co = this.relative_container.offset();
1465 this.containment[ 0 ] + co.left,
1466 this.containment[ 1 ] + co.top,
1467 this.containment[ 2 ] + co.left,
1468 this.containment[ 3 ] + co.top
1472 containment = this.containment;
1475 if(event.pageX - this.offset.click.left < containment[0]) {
1476 pageX = containment[0] + this.offset.click.left;
1478 if(event.pageY - this.offset.click.top < containment[1]) {
1479 pageY = containment[1] + this.offset.click.top;
1481 if(event.pageX - this.offset.click.left > containment[2]) {
1482 pageX = containment[2] + this.offset.click.left;
1484 if(event.pageY - this.offset.click.top > containment[3]) {
1485 pageY = containment[3] + this.offset.click.top;
1490 //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950)
1491 top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY;
1492 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;
1494 left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX;
1495 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;
1502 pageY - // The absolute mouse position
1503 this.offset.click.top - // Click offset (relative to the element)
1504 this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
1505 this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
1506 ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : this.offset.scroll.top )
1509 pageX - // The absolute mouse position
1510 this.offset.click.left - // Click offset (relative to the element)
1511 this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
1512 this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
1513 ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : this.offset.scroll.left )
1519 _clear: function() {
1520 this.helper.removeClass("ui-draggable-dragging");
1521 if(this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) {
1522 this.helper.remove();
1525 this.cancelHelperRemoval = false;
1528 // From now on bulk stuff - mainly helpers
1530 _trigger: function(type, event, ui) {
1531 ui = ui || this._uiHash();
1532 $.ui.plugin.call(this, type, [event, ui]);
1533 //The absolute position has to be recalculated after plugins
1534 if(type === "drag") {
1535 this.positionAbs = this._convertPositionTo("absolute");
1537 return $.Widget.prototype._trigger.call(this, type, event, ui);
1542 _uiHash: function() {
1544 helper: this.helper,
1545 position: this.position,
1546 originalPosition: this.originalPosition,
1547 offset: this.positionAbs
1553 $.ui.plugin.add("draggable", "connectToSortable", {
1554 start: function(event, ui) {
1556 var inst = $(this).data("ui-draggable"), o = inst.options,
1557 uiSortable = $.extend({}, ui, { item: inst.element });
1558 inst.sortables = [];
1559 $(o.connectToSortable).each(function() {
1560 var sortable = $.data(this, "ui-sortable");
1561 if (sortable && !sortable.options.disabled) {
1562 inst.sortables.push({
1564 shouldRevert: sortable.options.revert
1566 sortable.refreshPositions(); // Call the sortable's refreshPositions at drag start to refresh the containerCache since the sortable container cache is used in drag and needs to be up to date (this will ensure it's initialised as well as being kept in step with any changes that might have happened on the page).
1567 sortable._trigger("activate", event, uiSortable);
1572 stop: function(event, ui) {
1574 //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
1575 var inst = $(this).data("ui-draggable"),
1576 uiSortable = $.extend({}, ui, { item: inst.element });
1578 $.each(inst.sortables, function() {
1579 if(this.instance.isOver) {
1581 this.instance.isOver = 0;
1583 inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
1584 this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
1586 //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: "valid/invalid"
1587 if(this.shouldRevert) {
1588 this.instance.options.revert = this.shouldRevert;
1591 //Trigger the stop of the sortable
1592 this.instance._mouseStop(event);
1594 this.instance.options.helper = this.instance.options._helper;
1596 //If the helper has been the original item, restore properties in the sortable
1597 if(inst.options.helper === "original") {
1598 this.instance.currentItem.css({ top: "auto", left: "auto" });
1602 this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance
1603 this.instance._trigger("deactivate", event, uiSortable);
1609 drag: function(event, ui) {
1611 var inst = $(this).data("ui-draggable"), that = this;
1613 $.each(inst.sortables, function() {
1615 var innermostIntersecting = false,
1616 thisSortable = this;
1618 //Copy over some variables to allow calling the sortable's native _intersectsWith
1619 this.instance.positionAbs = inst.positionAbs;
1620 this.instance.helperProportions = inst.helperProportions;
1621 this.instance.offset.click = inst.offset.click;
1623 if(this.instance._intersectsWith(this.instance.containerCache)) {
1624 innermostIntersecting = true;
1625 $.each(inst.sortables, function () {
1626 this.instance.positionAbs = inst.positionAbs;
1627 this.instance.helperProportions = inst.helperProportions;
1628 this.instance.offset.click = inst.offset.click;
1629 if (this !== thisSortable &&
1630 this.instance._intersectsWith(this.instance.containerCache) &&
1631 $.contains(thisSortable.instance.element[0], this.instance.element[0])
1633 innermostIntersecting = false;
1635 return innermostIntersecting;
1640 if(innermostIntersecting) {
1641 //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
1642 if(!this.instance.isOver) {
1644 this.instance.isOver = 1;
1645 //Now we fake the start of dragging for the sortable instance,
1646 //by cloning the list group item, appending it to the sortable and using it as inst.currentItem
1647 //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one)
1648 this.instance.currentItem = $(that).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item", true);
1649 this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it
1650 this.instance.options.helper = function() { return ui.helper[0]; };
1652 event.target = this.instance.currentItem[0];
1653 this.instance._mouseCapture(event, true);
1654 this.instance._mouseStart(event, true, true);
1656 //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
1657 this.instance.offset.click.top = inst.offset.click.top;
1658 this.instance.offset.click.left = inst.offset.click.left;
1659 this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left;
1660 this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top;
1662 inst._trigger("toSortable", event);
1663 inst.dropped = this.instance.element; //draggable revert needs that
1664 //hack so receive/update callbacks work (mostly)
1665 inst.currentItem = inst.element;
1666 this.instance.fromOutside = inst;
1670 //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable
1671 if(this.instance.currentItem) {
1672 this.instance._mouseDrag(event);
1677 //If it doesn't intersect with the sortable, and it intersected before,
1678 //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
1679 if(this.instance.isOver) {
1681 this.instance.isOver = 0;
1682 this.instance.cancelHelperRemoval = true;
1684 //Prevent reverting on this forced stop
1685 this.instance.options.revert = false;
1687 // The out event needs to be triggered independently
1688 this.instance._trigger("out", event, this.instance._uiHash(this.instance));
1690 this.instance._mouseStop(event, true);
1691 this.instance.options.helper = this.instance.options._helper;
1693 //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
1694 this.instance.currentItem.remove();
1695 if(this.instance.placeholder) {
1696 this.instance.placeholder.remove();
1699 inst._trigger("fromSortable", event);
1700 inst.dropped = false; //draggable revert needs that
1710 $.ui.plugin.add("draggable", "cursor", {
1712 var t = $("body"), o = $(this).data("ui-draggable").options;
1713 if (t.css("cursor")) {
1714 o._cursor = t.css("cursor");
1716 t.css("cursor", o.cursor);
1719 var o = $(this).data("ui-draggable").options;
1721 $("body").css("cursor", o._cursor);
1726 $.ui.plugin.add("draggable", "opacity", {
1727 start: function(event, ui) {
1728 var t = $(ui.helper), o = $(this).data("ui-draggable").options;
1729 if(t.css("opacity")) {
1730 o._opacity = t.css("opacity");
1732 t.css("opacity", o.opacity);
1734 stop: function(event, ui) {
1735 var o = $(this).data("ui-draggable").options;
1737 $(ui.helper).css("opacity", o._opacity);
1742 $.ui.plugin.add("draggable", "scroll", {
1744 var i = $(this).data("ui-draggable");
1745 if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") {
1746 i.overflowOffset = i.scrollParent.offset();
1749 drag: function( event ) {
1751 var i = $(this).data("ui-draggable"), o = i.options, scrolled = false;
1753 if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") {
1755 if(!o.axis || o.axis !== "x") {
1756 if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
1757 i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
1758 } else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) {
1759 i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
1763 if(!o.axis || o.axis !== "y") {
1764 if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
1765 i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
1766 } else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) {
1767 i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
1773 if(!o.axis || o.axis !== "x") {
1774 if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
1775 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
1776 } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
1777 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
1781 if(!o.axis || o.axis !== "y") {
1782 if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
1783 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
1784 } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
1785 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
1791 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
1792 $.ui.ddmanager.prepareOffsets(i, event);
1798 $.ui.plugin.add("draggable", "snap", {
1801 var i = $(this).data("ui-draggable"),
1804 i.snapElements = [];
1806 $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() {
1809 if(this !== i.element[0]) {
1810 i.snapElements.push({
1812 width: $t.outerWidth(), height: $t.outerHeight(),
1813 top: $o.top, left: $o.left
1819 drag: function(event, ui) {
1821 var ts, bs, ls, rs, l, r, t, b, i, first,
1822 inst = $(this).data("ui-draggable"),
1824 d = o.snapTolerance,
1825 x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
1826 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
1828 for (i = inst.snapElements.length - 1; i >= 0; i--){
1830 l = inst.snapElements[i].left;
1831 r = l + inst.snapElements[i].width;
1832 t = inst.snapElements[i].top;
1833 b = t + inst.snapElements[i].height;
1835 if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || !$.contains( inst.snapElements[ i ].item.ownerDocument, inst.snapElements[ i ].item ) ) {
1836 if(inst.snapElements[i].snapping) {
1837 (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
1839 inst.snapElements[i].snapping = false;
1843 if(o.snapMode !== "inner") {
1844 ts = Math.abs(t - y2) <= d;
1845 bs = Math.abs(b - y1) <= d;
1846 ls = Math.abs(l - x2) <= d;
1847 rs = Math.abs(r - x1) <= d;
1849 ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
1852 ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top;
1855 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left;
1858 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left;
1862 first = (ts || bs || ls || rs);
1864 if(o.snapMode !== "outer") {
1865 ts = Math.abs(t - y1) <= d;
1866 bs = Math.abs(b - y2) <= d;
1867 ls = Math.abs(l - x1) <= d;
1868 rs = Math.abs(r - x2) <= d;
1870 ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top;
1873 ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
1876 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left;
1879 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left;
1883 if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) {
1884 (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
1886 inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
1893 $.ui.plugin.add("draggable", "stack", {
1896 o = this.data("ui-draggable").options,
1897 group = $.makeArray($(o.stack)).sort(function(a,b) {
1898 return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0);
1901 if (!group.length) { return; }
1903 min = parseInt($(group[0]).css("zIndex"), 10) || 0;
1904 $(group).each(function(i) {
1905 $(this).css("zIndex", min + i);
1907 this.css("zIndex", (min + group.length));
1911 $.ui.plugin.add("draggable", "zIndex", {
1912 start: function(event, ui) {
1913 var t = $(ui.helper), o = $(this).data("ui-draggable").options;
1914 if(t.css("zIndex")) {
1915 o._zIndex = t.css("zIndex");
1917 t.css("zIndex", o.zIndex);
1919 stop: function(event, ui) {
1920 var o = $(this).data("ui-draggable").options;
1922 $(ui.helper).css("zIndex", o._zIndex);
1929 (function( $, undefined ) {
1931 function isOverAxis( x, reference, size ) {
1932 return ( x > reference ) && ( x < ( reference + size ) );
1935 $.widget("ui.droppable", {
1937 widgetEventPrefix: "drop",
1945 tolerance: "intersect",
1954 _create: function() {
1956 var o = this.options,
1959 this.isover = false;
1962 this.accept = $.isFunction(accept) ? accept : function(d) {
1963 return d.is(accept);
1966 //Store the droppable's proportions
1967 this.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight };
1969 // Add the reference and positions to the manager
1970 $.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || [];
1971 $.ui.ddmanager.droppables[o.scope].push(this);
1973 (o.addClasses && this.element.addClass("ui-droppable"));
1977 _destroy: function() {
1979 drop = $.ui.ddmanager.droppables[this.options.scope];
1981 for ( ; i < drop.length; i++ ) {
1982 if ( drop[i] === this ) {
1987 this.element.removeClass("ui-droppable ui-droppable-disabled");
1990 _setOption: function(key, value) {
1992 if(key === "accept") {
1993 this.accept = $.isFunction(value) ? value : function(d) {
1997 $.Widget.prototype._setOption.apply(this, arguments);
2000 _activate: function(event) {
2001 var draggable = $.ui.ddmanager.current;
2002 if(this.options.activeClass) {
2003 this.element.addClass(this.options.activeClass);
2006 this._trigger("activate", event, this.ui(draggable));
2010 _deactivate: function(event) {
2011 var draggable = $.ui.ddmanager.current;
2012 if(this.options.activeClass) {
2013 this.element.removeClass(this.options.activeClass);
2016 this._trigger("deactivate", event, this.ui(draggable));
2020 _over: function(event) {
2022 var draggable = $.ui.ddmanager.current;
2024 // Bail if draggable and droppable are same element
2025 if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {
2029 if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
2030 if(this.options.hoverClass) {
2031 this.element.addClass(this.options.hoverClass);
2033 this._trigger("over", event, this.ui(draggable));
2038 _out: function(event) {
2040 var draggable = $.ui.ddmanager.current;
2042 // Bail if draggable and droppable are same element
2043 if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {
2047 if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
2048 if(this.options.hoverClass) {
2049 this.element.removeClass(this.options.hoverClass);
2051 this._trigger("out", event, this.ui(draggable));
2056 _drop: function(event,custom) {
2058 var draggable = custom || $.ui.ddmanager.current,
2059 childrenIntersection = false;
2061 // Bail if draggable and droppable are same element
2062 if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {
2066 this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function() {
2067 var inst = $.data(this, "ui-droppable");
2069 inst.options.greedy &&
2070 !inst.options.disabled &&
2071 inst.options.scope === draggable.options.scope &&
2072 inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element)) &&
2073 $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance)
2074 ) { childrenIntersection = true; return false; }
2076 if(childrenIntersection) {
2080 if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
2081 if(this.options.activeClass) {
2082 this.element.removeClass(this.options.activeClass);
2084 if(this.options.hoverClass) {
2085 this.element.removeClass(this.options.hoverClass);
2087 this._trigger("drop", event, this.ui(draggable));
2088 return this.element;
2097 draggable: (c.currentItem || c.element),
2099 position: c.position,
2100 offset: c.positionAbs
2106 $.ui.intersect = function(draggable, droppable, toleranceMode) {
2108 if (!droppable.offset) {
2112 var draggableLeft, draggableTop,
2113 x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width,
2114 y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height,
2115 l = droppable.offset.left, r = l + droppable.proportions.width,
2116 t = droppable.offset.top, b = t + droppable.proportions.height;
2118 switch (toleranceMode) {
2120 return (l <= x1 && x2 <= r && t <= y1 && y2 <= b);
2122 return (l < x1 + (draggable.helperProportions.width / 2) && // Right Half
2123 x2 - (draggable.helperProportions.width / 2) < r && // Left Half
2124 t < y1 + (draggable.helperProportions.height / 2) && // Bottom Half
2125 y2 - (draggable.helperProportions.height / 2) < b ); // Top Half
2127 draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left);
2128 draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top);
2129 return isOverAxis( draggableTop, t, droppable.proportions.height ) && isOverAxis( draggableLeft, l, droppable.proportions.width );
2132 (y1 >= t && y1 <= b) || // Top edge touching
2133 (y2 >= t && y2 <= b) || // Bottom edge touching
2134 (y1 < t && y2 > b) // Surrounded vertically
2136 (x1 >= l && x1 <= r) || // Left edge touching
2137 (x2 >= l && x2 <= r) || // Right edge touching
2138 (x1 < l && x2 > r) // Surrounded horizontally
2147 This manager tracks offsets of draggables and droppables
2151 droppables: { "default": [] },
2152 prepareOffsets: function(t, event) {
2155 m = $.ui.ddmanager.droppables[t.options.scope] || [],
2156 type = event ? event.type : null, // workaround for #2317
2157 list = (t.currentItem || t.element).find(":data(ui-droppable)").addBack();
2159 droppablesLoop: for (i = 0; i < m.length; i++) {
2161 //No disabled and non-accepted
2162 if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) {
2166 // Filter out elements in the current dragged item
2167 for (j=0; j < list.length; j++) {
2168 if(list[j] === m[i].element[0]) {
2169 m[i].proportions.height = 0;
2170 continue droppablesLoop;
2174 m[i].visible = m[i].element.css("display") !== "none";
2179 //Activate the droppable if used directly from draggables
2180 if(type === "mousedown") {
2181 m[i]._activate.call(m[i], event);
2184 m[i].offset = m[i].element.offset();
2185 m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight };
2190 drop: function(draggable, event) {
2192 var dropped = false;
2193 // Create a copy of the droppables in case the list changes during the drop (#9116)
2194 $.each(($.ui.ddmanager.droppables[draggable.options.scope] || []).slice(), function() {
2199 if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance)) {
2200 dropped = this._drop.call(this, event) || dropped;
2203 if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
2205 this.isover = false;
2206 this._deactivate.call(this, event);
2213 dragStart: function( draggable, event ) {
2214 //Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003)
2215 draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() {
2216 if( !draggable.options.refreshPositions ) {
2217 $.ui.ddmanager.prepareOffsets( draggable, event );
2221 drag: function(draggable, event) {
2223 //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
2224 if(draggable.options.refreshPositions) {
2225 $.ui.ddmanager.prepareOffsets(draggable, event);
2228 //Run through all droppables and check their positions based on specific tolerance options
2229 $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {
2231 if(this.options.disabled || this.greedyChild || !this.visible) {
2235 var parentInstance, scope, parent,
2236 intersects = $.ui.intersect(draggable, this, this.options.tolerance),
2237 c = !intersects && this.isover ? "isout" : (intersects && !this.isover ? "isover" : null);
2242 if (this.options.greedy) {
2243 // find droppable parents with same scope
2244 scope = this.options.scope;
2245 parent = this.element.parents(":data(ui-droppable)").filter(function () {
2246 return $.data(this, "ui-droppable").options.scope === scope;
2249 if (parent.length) {
2250 parentInstance = $.data(parent[0], "ui-droppable");
2251 parentInstance.greedyChild = (c === "isover");
2255 // we just moved into a greedy child
2256 if (parentInstance && c === "isover") {
2257 parentInstance.isover = false;
2258 parentInstance.isout = true;
2259 parentInstance._out.call(parentInstance, event);
2263 this[c === "isout" ? "isover" : "isout"] = false;
2264 this[c === "isover" ? "_over" : "_out"].call(this, event);
2266 // we just moved out of a greedy child
2267 if (parentInstance && c === "isout") {
2268 parentInstance.isout = false;
2269 parentInstance.isover = true;
2270 parentInstance._over.call(parentInstance, event);
2275 dragStop: function( draggable, event ) {
2276 draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" );
2277 //Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003)
2278 if( !draggable.options.refreshPositions ) {
2279 $.ui.ddmanager.prepareOffsets( draggable, event );
2286 (function( $, undefined ) {
2289 return parseInt(v, 10) || 0;
2292 function isNumber(value) {
2293 return !isNaN(parseInt(value, 10));
2296 $.widget("ui.resizable", $.ui.mouse, {
2298 widgetEventPrefix: "resize",
2302 animateDuration: "slow",
2303 animateEasing: "swing",
2323 _create: function() {
2325 var n, i, handle, axis, hname,
2328 this.element.addClass("ui-resizable");
2331 _aspectRatio: !!(o.aspectRatio),
2332 aspectRatio: o.aspectRatio,
2333 originalElement: this.element,
2334 _proportionallyResizeElements: [],
2335 _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
2338 //Wrap the element if it cannot hold child nodes
2339 if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) {
2341 //Create a wrapper element and set the wrapper to the new current internal element
2343 $("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({
2344 position: this.element.css("position"),
2345 width: this.element.outerWidth(),
2346 height: this.element.outerHeight(),
2347 top: this.element.css("top"),
2348 left: this.element.css("left")
2352 //Overwrite the original this.element
2353 this.element = this.element.parent().data(
2354 "ui-resizable", this.element.data("ui-resizable")
2357 this.elementIsWrapper = true;
2359 //Move margins to the wrapper
2360 this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") });
2361 this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0});
2363 //Prevent Safari textarea resize
2364 this.originalResizeStyle = this.originalElement.css("resize");
2365 this.originalElement.css("resize", "none");
2367 //Push the actual element to our proportionallyResize internal array
2368 this._proportionallyResizeElements.push(this.originalElement.css({ position: "static", zoom: 1, display: "block" }));
2370 // avoid IE jump (hard set the margin)
2371 this.originalElement.css({ margin: this.originalElement.css("margin") });
2373 // fix handlers offset
2374 this._proportionallyResize();
2378 this.handles = o.handles || (!$(".ui-resizable-handle", this.element).length ? "e,s,se" : { n: ".ui-resizable-n", e: ".ui-resizable-e", s: ".ui-resizable-s", w: ".ui-resizable-w", se: ".ui-resizable-se", sw: ".ui-resizable-sw", ne: ".ui-resizable-ne", nw: ".ui-resizable-nw" });
2379 if(this.handles.constructor === String) {
2381 if ( this.handles === "all") {
2382 this.handles = "n,e,s,w,se,sw,ne,nw";
2385 n = this.handles.split(",");
2388 for(i = 0; i < n.length; i++) {
2390 handle = $.trim(n[i]);
2391 hname = "ui-resizable-"+handle;
2392 axis = $("<div class='ui-resizable-handle " + hname + "'></div>");
2394 // Apply zIndex to all handles - see #7960
2395 axis.css({ zIndex: o.zIndex });
2397 //TODO : What's going on here?
2398 if ("se" === handle) {
2399 axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se");
2402 //Insert into internal handles object and append to element
2403 this.handles[handle] = ".ui-resizable-"+handle;
2404 this.element.append(axis);
2409 this._renderAxis = function(target) {
2411 var i, axis, padPos, padWrapper;
2413 target = target || this.element;
2415 for(i in this.handles) {
2417 if(this.handles[i].constructor === String) {
2418 this.handles[i] = $(this.handles[i], this.element).show();
2421 //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls)
2422 if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) {
2424 axis = $(this.handles[i], this.element);
2426 //Checking the correct pad and border
2427 padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
2429 //The padding type i have to apply...
2430 padPos = [ "padding",
2431 /ne|nw|n/.test(i) ? "Top" :
2432 /se|sw|s/.test(i) ? "Bottom" :
2433 /^e$/.test(i) ? "Right" : "Left" ].join("");
2435 target.css(padPos, padWrapper);
2437 this._proportionallyResize();
2441 //TODO: What's that good for? There's not anything to be executed left
2442 if(!$(this.handles[i]).length) {
2448 //TODO: make renderAxis a prototype function
2449 this._renderAxis(this.element);
2451 this._handles = $(".ui-resizable-handle", this.element)
2452 .disableSelection();
2454 //Matching axis name
2455 this._handles.mouseover(function() {
2456 if (!that.resizing) {
2457 if (this.className) {
2458 axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
2460 //Axis, default = se
2461 that.axis = axis && axis[1] ? axis[1] : "se";
2465 //If we want to auto hide the elements
2467 this._handles.hide();
2469 .addClass("ui-resizable-autohide")
2470 .mouseenter(function() {
2474 $(this).removeClass("ui-resizable-autohide");
2475 that._handles.show();
2477 .mouseleave(function(){
2481 if (!that.resizing) {
2482 $(this).addClass("ui-resizable-autohide");
2483 that._handles.hide();
2488 //Initialize the mouse interaction
2493 _destroy: function() {
2495 this._mouseDestroy();
2498 _destroy = function(exp) {
2499 $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing")
2500 .removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove();
2503 //TODO: Unwrap at same DOM position
2504 if (this.elementIsWrapper) {
2505 _destroy(this.element);
2506 wrapper = this.element;
2507 this.originalElement.css({
2508 position: wrapper.css("position"),
2509 width: wrapper.outerWidth(),
2510 height: wrapper.outerHeight(),
2511 top: wrapper.css("top"),
2512 left: wrapper.css("left")
2513 }).insertAfter( wrapper );
2517 this.originalElement.css("resize", this.originalResizeStyle);
2518 _destroy(this.originalElement);
2523 _mouseCapture: function(event) {
2527 for (i in this.handles) {
2528 handle = $(this.handles[i])[0];
2529 if (handle === event.target || $.contains(handle, event.target)) {
2534 return !this.options.disabled && capture;
2537 _mouseStart: function(event) {
2539 var curleft, curtop, cursor,
2541 iniPos = this.element.position(),
2544 this.resizing = true;
2546 // bugfix for http://dev.jquery.com/ticket/1749
2547 if ( (/absolute/).test( el.css("position") ) ) {
2548 el.css({ position: "absolute", top: el.css("top"), left: el.css("left") });
2549 } else if (el.is(".ui-draggable")) {
2550 el.css({ position: "absolute", top: iniPos.top, left: iniPos.left });
2553 this._renderProxy();
2555 curleft = num(this.helper.css("left"));
2556 curtop = num(this.helper.css("top"));
2558 if (o.containment) {
2559 curleft += $(o.containment).scrollLeft() || 0;
2560 curtop += $(o.containment).scrollTop() || 0;
2563 //Store needed variables
2564 this.offset = this.helper.offset();
2565 this.position = { left: curleft, top: curtop };
2566 this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
2567 this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
2568 this.originalPosition = { left: curleft, top: curtop };
2569 this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() };
2570 this.originalMousePosition = { left: event.pageX, top: event.pageY };
2573 this.aspectRatio = (typeof o.aspectRatio === "number") ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1);
2575 cursor = $(".ui-resizable-" + this.axis).css("cursor");
2576 $("body").css("cursor", cursor === "auto" ? this.axis + "-resize" : cursor);
2578 el.addClass("ui-resizable-resizing");
2579 this._propagate("start", event);
2583 _mouseDrag: function(event) {
2585 //Increase performance, avoid regex
2587 el = this.helper, props = {},
2588 smp = this.originalMousePosition,
2590 prevTop = this.position.top,
2591 prevLeft = this.position.left,
2592 prevWidth = this.size.width,
2593 prevHeight = this.size.height,
2594 dx = (event.pageX-smp.left)||0,
2595 dy = (event.pageY-smp.top)||0,
2596 trigger = this._change[a];
2602 // Calculate the attrs that will be change
2603 data = trigger.apply(this, [event, dx, dy]);
2605 // Put this in the mouseDrag handler since the user can start pressing shift while resizing
2606 this._updateVirtualBoundaries(event.shiftKey);
2607 if (this._aspectRatio || event.shiftKey) {
2608 data = this._updateRatio(data, event);
2611 data = this._respectSize(data, event);
2613 this._updateCache(data);
2615 // plugins callbacks need to be called first
2616 this._propagate("resize", event);
2618 if (this.position.top !== prevTop) {
2619 props.top = this.position.top + "px";
2621 if (this.position.left !== prevLeft) {
2622 props.left = this.position.left + "px";
2624 if (this.size.width !== prevWidth) {
2625 props.width = this.size.width + "px";
2627 if (this.size.height !== prevHeight) {
2628 props.height = this.size.height + "px";
2632 if (!this._helper && this._proportionallyResizeElements.length) {
2633 this._proportionallyResize();
2636 // Call the user callback if the element was resized
2637 if ( ! $.isEmptyObject(props) ) {
2638 this._trigger("resize", event, this.ui());
2644 _mouseStop: function(event) {
2646 this.resizing = false;
2647 var pr, ista, soffseth, soffsetw, s, left, top,
2648 o = this.options, that = this;
2652 pr = this._proportionallyResizeElements;
2653 ista = pr.length && (/textarea/i).test(pr[0].nodeName);
2654 soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height;
2655 soffsetw = ista ? 0 : that.sizeDiff.width;
2657 s = { width: (that.helper.width() - soffsetw), height: (that.helper.height() - soffseth) };
2658 left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null;
2659 top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null;
2662 this.element.css($.extend(s, { top: top, left: left }));
2665 that.helper.height(that.size.height);
2666 that.helper.width(that.size.width);
2668 if (this._helper && !o.animate) {
2669 this._proportionallyResize();
2673 $("body").css("cursor", "auto");
2675 this.element.removeClass("ui-resizable-resizing");
2677 this._propagate("stop", event);
2680 this.helper.remove();
2687 _updateVirtualBoundaries: function(forceAspectRatio) {
2688 var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
2692 minWidth: isNumber(o.minWidth) ? o.minWidth : 0,
2693 maxWidth: isNumber(o.maxWidth) ? o.maxWidth : Infinity,
2694 minHeight: isNumber(o.minHeight) ? o.minHeight : 0,
2695 maxHeight: isNumber(o.maxHeight) ? o.maxHeight : Infinity
2698 if(this._aspectRatio || forceAspectRatio) {
2699 // We want to create an enclosing box whose aspect ration is the requested one
2700 // First, compute the "projected" size for each dimension based on the aspect ratio and other dimension
2701 pMinWidth = b.minHeight * this.aspectRatio;
2702 pMinHeight = b.minWidth / this.aspectRatio;
2703 pMaxWidth = b.maxHeight * this.aspectRatio;
2704 pMaxHeight = b.maxWidth / this.aspectRatio;
2706 if(pMinWidth > b.minWidth) {
2707 b.minWidth = pMinWidth;
2709 if(pMinHeight > b.minHeight) {
2710 b.minHeight = pMinHeight;
2712 if(pMaxWidth < b.maxWidth) {
2713 b.maxWidth = pMaxWidth;
2715 if(pMaxHeight < b.maxHeight) {
2716 b.maxHeight = pMaxHeight;
2719 this._vBoundaries = b;
2722 _updateCache: function(data) {
2723 this.offset = this.helper.offset();
2724 if (isNumber(data.left)) {
2725 this.position.left = data.left;
2727 if (isNumber(data.top)) {
2728 this.position.top = data.top;
2730 if (isNumber(data.height)) {
2731 this.size.height = data.height;
2733 if (isNumber(data.width)) {
2734 this.size.width = data.width;