wp/wp-includes/js/jquery/ui/draggable.js
changeset 18 be944660c56a
child 19 3d72ae0968f4
equal deleted inserted replaced
17:34716fd837a4 18:be944660c56a
       
     1 /*!
       
     2  * jQuery UI Draggable 1.12.1
       
     3  * http://jqueryui.com
       
     4  *
       
     5  * Copyright jQuery Foundation and other contributors
       
     6  * Released under the MIT license.
       
     7  * http://jquery.org/license
       
     8  */
       
     9 
       
    10 //>>label: Draggable
       
    11 //>>group: Interactions
       
    12 //>>description: Enables dragging functionality for any element.
       
    13 //>>docs: http://api.jqueryui.com/draggable/
       
    14 //>>demos: http://jqueryui.com/draggable/
       
    15 //>>css.structure: ../../themes/base/draggable.css
       
    16 
       
    17 ( function( factory ) {
       
    18 	if ( typeof define === "function" && define.amd ) {
       
    19 
       
    20 		// AMD. Register as an anonymous module.
       
    21 		define( [
       
    22 			"jquery",
       
    23 			"./mouse",
       
    24 			"./core"
       
    25 		], factory );
       
    26 	} else {
       
    27 
       
    28 		// Browser globals
       
    29 		factory( jQuery );
       
    30 	}
       
    31 }( function( $ ) {
       
    32 
       
    33 $.widget( "ui.draggable", $.ui.mouse, {
       
    34 	version: "1.12.1",
       
    35 	widgetEventPrefix: "drag",
       
    36 	options: {
       
    37 		addClasses: true,
       
    38 		appendTo: "parent",
       
    39 		axis: false,
       
    40 		connectToSortable: false,
       
    41 		containment: false,
       
    42 		cursor: "auto",
       
    43 		cursorAt: false,
       
    44 		grid: false,
       
    45 		handle: false,
       
    46 		helper: "original",
       
    47 		iframeFix: false,
       
    48 		opacity: false,
       
    49 		refreshPositions: false,
       
    50 		revert: false,
       
    51 		revertDuration: 500,
       
    52 		scope: "default",
       
    53 		scroll: true,
       
    54 		scrollSensitivity: 20,
       
    55 		scrollSpeed: 20,
       
    56 		snap: false,
       
    57 		snapMode: "both",
       
    58 		snapTolerance: 20,
       
    59 		stack: false,
       
    60 		zIndex: false,
       
    61 
       
    62 		// Callbacks
       
    63 		drag: null,
       
    64 		start: null,
       
    65 		stop: null
       
    66 	},
       
    67 	_create: function() {
       
    68 
       
    69 		if ( this.options.helper === "original" ) {
       
    70 			this._setPositionRelative();
       
    71 		}
       
    72 		if ( this.options.addClasses ) {
       
    73 			this._addClass( "ui-draggable" );
       
    74 		}
       
    75 		this._setHandleClassName();
       
    76 
       
    77 		this._mouseInit();
       
    78 	},
       
    79 
       
    80 	_setOption: function( key, value ) {
       
    81 		this._super( key, value );
       
    82 		if ( key === "handle" ) {
       
    83 			this._removeHandleClassName();
       
    84 			this._setHandleClassName();
       
    85 		}
       
    86 	},
       
    87 
       
    88 	_destroy: function() {
       
    89 		if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) {
       
    90 			this.destroyOnClear = true;
       
    91 			return;
       
    92 		}
       
    93 		this._removeHandleClassName();
       
    94 		this._mouseDestroy();
       
    95 	},
       
    96 
       
    97 	_mouseCapture: function( event ) {
       
    98 		var o = this.options;
       
    99 
       
   100 		// Among others, prevent a drag on a resizable-handle
       
   101 		if ( this.helper || o.disabled ||
       
   102 				$( event.target ).closest( ".ui-resizable-handle" ).length > 0 ) {
       
   103 			return false;
       
   104 		}
       
   105 
       
   106 		//Quit if we're not on a valid handle
       
   107 		this.handle = this._getHandle( event );
       
   108 		if ( !this.handle ) {
       
   109 			return false;
       
   110 		}
       
   111 
       
   112 		this._blurActiveElement( event );
       
   113 
       
   114 		this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix );
       
   115 
       
   116 		return true;
       
   117 
       
   118 	},
       
   119 
       
   120 	_blockFrames: function( selector ) {
       
   121 		this.iframeBlocks = this.document.find( selector ).map( function() {
       
   122 			var iframe = $( this );
       
   123 
       
   124 			return $( "<div>" )
       
   125 				.css( "position", "absolute" )
       
   126 				.appendTo( iframe.parent() )
       
   127 				.outerWidth( iframe.outerWidth() )
       
   128 				.outerHeight( iframe.outerHeight() )
       
   129 				.offset( iframe.offset() )[ 0 ];
       
   130 		} );
       
   131 	},
       
   132 
       
   133 	_unblockFrames: function() {
       
   134 		if ( this.iframeBlocks ) {
       
   135 			this.iframeBlocks.remove();
       
   136 			delete this.iframeBlocks;
       
   137 		}
       
   138 	},
       
   139 
       
   140 	_blurActiveElement: function( event ) {
       
   141 		var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ),
       
   142 			target = $( event.target );
       
   143 
       
   144 		// Don't blur if the event occurred on an element that is within
       
   145 		// the currently focused element
       
   146 		// See #10527, #12472
       
   147 		if ( target.closest( activeElement ).length ) {
       
   148 			return;
       
   149 		}
       
   150 
       
   151 		// Blur any element that currently has focus, see #4261
       
   152 		$.ui.safeBlur( activeElement );
       
   153 	},
       
   154 
       
   155 	_mouseStart: function( event ) {
       
   156 
       
   157 		var o = this.options;
       
   158 
       
   159 		//Create and append the visible helper
       
   160 		this.helper = this._createHelper( event );
       
   161 
       
   162 		this._addClass( this.helper, "ui-draggable-dragging" );
       
   163 
       
   164 		//Cache the helper size
       
   165 		this._cacheHelperProportions();
       
   166 
       
   167 		//If ddmanager is used for droppables, set the global draggable
       
   168 		if ( $.ui.ddmanager ) {
       
   169 			$.ui.ddmanager.current = this;
       
   170 		}
       
   171 
       
   172 		/*
       
   173 		 * - Position generation -
       
   174 		 * This block generates everything position related - it's the core of draggables.
       
   175 		 */
       
   176 
       
   177 		//Cache the margins of the original element
       
   178 		this._cacheMargins();
       
   179 
       
   180 		//Store the helper's css position
       
   181 		this.cssPosition = this.helper.css( "position" );
       
   182 		this.scrollParent = this.helper.scrollParent( true );
       
   183 		this.offsetParent = this.helper.offsetParent();
       
   184 		this.hasFixedAncestor = this.helper.parents().filter( function() {
       
   185 				return $( this ).css( "position" ) === "fixed";
       
   186 			} ).length > 0;
       
   187 
       
   188 		//The element's absolute position on the page minus margins
       
   189 		this.positionAbs = this.element.offset();
       
   190 		this._refreshOffsets( event );
       
   191 
       
   192 		//Generate the original position
       
   193 		this.originalPosition = this.position = this._generatePosition( event, false );
       
   194 		this.originalPageX = event.pageX;
       
   195 		this.originalPageY = event.pageY;
       
   196 
       
   197 		//Adjust the mouse offset relative to the helper if "cursorAt" is supplied
       
   198 		( o.cursorAt && this._adjustOffsetFromHelper( o.cursorAt ) );
       
   199 
       
   200 		//Set a containment if given in the options
       
   201 		this._setContainment();
       
   202 
       
   203 		//Trigger event + callbacks
       
   204 		if ( this._trigger( "start", event ) === false ) {
       
   205 			this._clear();
       
   206 			return false;
       
   207 		}
       
   208 
       
   209 		//Recache the helper size
       
   210 		this._cacheHelperProportions();
       
   211 
       
   212 		//Prepare the droppable offsets
       
   213 		if ( $.ui.ddmanager && !o.dropBehaviour ) {
       
   214 			$.ui.ddmanager.prepareOffsets( this, event );
       
   215 		}
       
   216 
       
   217 		// Execute the drag once - this causes the helper not to be visible before getting its
       
   218 		// correct position
       
   219 		this._mouseDrag( event, true );
       
   220 
       
   221 		// If the ddmanager is used for droppables, inform the manager that dragging has started
       
   222 		// (see #5003)
       
   223 		if ( $.ui.ddmanager ) {
       
   224 			$.ui.ddmanager.dragStart( this, event );
       
   225 		}
       
   226 
       
   227 		return true;
       
   228 	},
       
   229 
       
   230 	_refreshOffsets: function( event ) {
       
   231 		this.offset = {
       
   232 			top: this.positionAbs.top - this.margins.top,
       
   233 			left: this.positionAbs.left - this.margins.left,
       
   234 			scroll: false,
       
   235 			parent: this._getParentOffset(),
       
   236 			relative: this._getRelativeOffset()
       
   237 		};
       
   238 
       
   239 		this.offset.click = {
       
   240 			left: event.pageX - this.offset.left,
       
   241 			top: event.pageY - this.offset.top
       
   242 		};
       
   243 	},
       
   244 
       
   245 	_mouseDrag: function( event, noPropagation ) {
       
   246 
       
   247 		// reset any necessary cached properties (see #5009)
       
   248 		if ( this.hasFixedAncestor ) {
       
   249 			this.offset.parent = this._getParentOffset();
       
   250 		}
       
   251 
       
   252 		//Compute the helpers position
       
   253 		this.position = this._generatePosition( event, true );
       
   254 		this.positionAbs = this._convertPositionTo( "absolute" );
       
   255 
       
   256 		//Call plugins and callbacks and use the resulting position if something is returned
       
   257 		if ( !noPropagation ) {
       
   258 			var ui = this._uiHash();
       
   259 			if ( this._trigger( "drag", event, ui ) === false ) {
       
   260 				this._mouseUp( new $.Event( "mouseup", event ) );
       
   261 				return false;
       
   262 			}
       
   263 			this.position = ui.position;
       
   264 		}
       
   265 
       
   266 		this.helper[ 0 ].style.left = this.position.left + "px";
       
   267 		this.helper[ 0 ].style.top = this.position.top + "px";
       
   268 
       
   269 		if ( $.ui.ddmanager ) {
       
   270 			$.ui.ddmanager.drag( this, event );
       
   271 		}
       
   272 
       
   273 		return false;
       
   274 	},
       
   275 
       
   276 	_mouseStop: function( event ) {
       
   277 
       
   278 		//If we are using droppables, inform the manager about the drop
       
   279 		var that = this,
       
   280 			dropped = false;
       
   281 		if ( $.ui.ddmanager && !this.options.dropBehaviour ) {
       
   282 			dropped = $.ui.ddmanager.drop( this, event );
       
   283 		}
       
   284 
       
   285 		//if a drop comes from outside (a sortable)
       
   286 		if ( this.dropped ) {
       
   287 			dropped = this.dropped;
       
   288 			this.dropped = false;
       
   289 		}
       
   290 
       
   291 		if ( ( this.options.revert === "invalid" && !dropped ) ||
       
   292 				( this.options.revert === "valid" && dropped ) ||
       
   293 				this.options.revert === true || ( $.isFunction( this.options.revert ) &&
       
   294 				this.options.revert.call( this.element, dropped ) )
       
   295 		) {
       
   296 			$( this.helper ).animate(
       
   297 				this.originalPosition,
       
   298 				parseInt( this.options.revertDuration, 10 ),
       
   299 				function() {
       
   300 					if ( that._trigger( "stop", event ) !== false ) {
       
   301 						that._clear();
       
   302 					}
       
   303 				}
       
   304 			);
       
   305 		} else {
       
   306 			if ( this._trigger( "stop", event ) !== false ) {
       
   307 				this._clear();
       
   308 			}
       
   309 		}
       
   310 
       
   311 		return false;
       
   312 	},
       
   313 
       
   314 	_mouseUp: function( event ) {
       
   315 		this._unblockFrames();
       
   316 
       
   317 		// If the ddmanager is used for droppables, inform the manager that dragging has stopped
       
   318 		// (see #5003)
       
   319 		if ( $.ui.ddmanager ) {
       
   320 			$.ui.ddmanager.dragStop( this, event );
       
   321 		}
       
   322 
       
   323 		// Only need to focus if the event occurred on the draggable itself, see #10527
       
   324 		if ( this.handleElement.is( event.target ) ) {
       
   325 
       
   326 			// The interaction is over; whether or not the click resulted in a drag,
       
   327 			// focus the element
       
   328 			this.element.trigger( "focus" );
       
   329 		}
       
   330 
       
   331 		return $.ui.mouse.prototype._mouseUp.call( this, event );
       
   332 	},
       
   333 
       
   334 	cancel: function() {
       
   335 
       
   336 		if ( this.helper.is( ".ui-draggable-dragging" ) ) {
       
   337 			this._mouseUp( new $.Event( "mouseup", { target: this.element[ 0 ] } ) );
       
   338 		} else {
       
   339 			this._clear();
       
   340 		}
       
   341 
       
   342 		return this;
       
   343 
       
   344 	},
       
   345 
       
   346 	_getHandle: function( event ) {
       
   347 		return this.options.handle ?
       
   348 			!!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
       
   349 			true;
       
   350 	},
       
   351 
       
   352 	_setHandleClassName: function() {
       
   353 		this.handleElement = this.options.handle ?
       
   354 			this.element.find( this.options.handle ) : this.element;
       
   355 		this._addClass( this.handleElement, "ui-draggable-handle" );
       
   356 	},
       
   357 
       
   358 	_removeHandleClassName: function() {
       
   359 		this._removeClass( this.handleElement, "ui-draggable-handle" );
       
   360 	},
       
   361 
       
   362 	_createHelper: function( event ) {
       
   363 
       
   364 		var o = this.options,
       
   365 			helperIsFunction = $.isFunction( o.helper ),
       
   366 			helper = helperIsFunction ?
       
   367 				$( o.helper.apply( this.element[ 0 ], [ event ] ) ) :
       
   368 				( o.helper === "clone" ?
       
   369 					this.element.clone().removeAttr( "id" ) :
       
   370 					this.element );
       
   371 
       
   372 		if ( !helper.parents( "body" ).length ) {
       
   373 			helper.appendTo( ( o.appendTo === "parent" ?
       
   374 				this.element[ 0 ].parentNode :
       
   375 				o.appendTo ) );
       
   376 		}
       
   377 
       
   378 		// Http://bugs.jqueryui.com/ticket/9446
       
   379 		// a helper function can return the original element
       
   380 		// which wouldn't have been set to relative in _create
       
   381 		if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) {
       
   382 			this._setPositionRelative();
       
   383 		}
       
   384 
       
   385 		if ( helper[ 0 ] !== this.element[ 0 ] &&
       
   386 				!( /(fixed|absolute)/ ).test( helper.css( "position" ) ) ) {
       
   387 			helper.css( "position", "absolute" );
       
   388 		}
       
   389 
       
   390 		return helper;
       
   391 
       
   392 	},
       
   393 
       
   394 	_setPositionRelative: function() {
       
   395 		if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) {
       
   396 			this.element[ 0 ].style.position = "relative";
       
   397 		}
       
   398 	},
       
   399 
       
   400 	_adjustOffsetFromHelper: function( obj ) {
       
   401 		if ( typeof obj === "string" ) {
       
   402 			obj = obj.split( " " );
       
   403 		}
       
   404 		if ( $.isArray( obj ) ) {
       
   405 			obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 };
       
   406 		}
       
   407 		if ( "left" in obj ) {
       
   408 			this.offset.click.left = obj.left + this.margins.left;
       
   409 		}
       
   410 		if ( "right" in obj ) {
       
   411 			this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
       
   412 		}
       
   413 		if ( "top" in obj ) {
       
   414 			this.offset.click.top = obj.top + this.margins.top;
       
   415 		}
       
   416 		if ( "bottom" in obj ) {
       
   417 			this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
       
   418 		}
       
   419 	},
       
   420 
       
   421 	_isRootNode: function( element ) {
       
   422 		return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ];
       
   423 	},
       
   424 
       
   425 	_getParentOffset: function() {
       
   426 
       
   427 		//Get the offsetParent and cache its position
       
   428 		var po = this.offsetParent.offset(),
       
   429 			document = this.document[ 0 ];
       
   430 
       
   431 		// This is a special case where we need to modify a offset calculated on start, since the
       
   432 		// following happened:
       
   433 		// 1. The position of the helper is absolute, so it's position is calculated based on the
       
   434 		// next positioned parent
       
   435 		// 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't
       
   436 		// the document, which means that the scroll is included in the initial calculation of the
       
   437 		// offset of the parent, and never recalculated upon drag
       
   438 		if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== document &&
       
   439 				$.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) {
       
   440 			po.left += this.scrollParent.scrollLeft();
       
   441 			po.top += this.scrollParent.scrollTop();
       
   442 		}
       
   443 
       
   444 		if ( this._isRootNode( this.offsetParent[ 0 ] ) ) {
       
   445 			po = { top: 0, left: 0 };
       
   446 		}
       
   447 
       
   448 		return {
       
   449 			top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ),
       
   450 			left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 )
       
   451 		};
       
   452 
       
   453 	},
       
   454 
       
   455 	_getRelativeOffset: function() {
       
   456 		if ( this.cssPosition !== "relative" ) {
       
   457 			return { top: 0, left: 0 };
       
   458 		}
       
   459 
       
   460 		var p = this.element.position(),
       
   461 			scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
       
   462 
       
   463 		return {
       
   464 			top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) +
       
   465 				( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ),
       
   466 			left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) +
       
   467 				( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 )
       
   468 		};
       
   469 
       
   470 	},
       
   471 
       
   472 	_cacheMargins: function() {
       
   473 		this.margins = {
       
   474 			left: ( parseInt( this.element.css( "marginLeft" ), 10 ) || 0 ),
       
   475 			top: ( parseInt( this.element.css( "marginTop" ), 10 ) || 0 ),
       
   476 			right: ( parseInt( this.element.css( "marginRight" ), 10 ) || 0 ),
       
   477 			bottom: ( parseInt( this.element.css( "marginBottom" ), 10 ) || 0 )
       
   478 		};
       
   479 	},
       
   480 
       
   481 	_cacheHelperProportions: function() {
       
   482 		this.helperProportions = {
       
   483 			width: this.helper.outerWidth(),
       
   484 			height: this.helper.outerHeight()
       
   485 		};
       
   486 	},
       
   487 
       
   488 	_setContainment: function() {
       
   489 
       
   490 		var isUserScrollable, c, ce,
       
   491 			o = this.options,
       
   492 			document = this.document[ 0 ];
       
   493 
       
   494 		this.relativeContainer = null;
       
   495 
       
   496 		if ( !o.containment ) {
       
   497 			this.containment = null;
       
   498 			return;
       
   499 		}
       
   500 
       
   501 		if ( o.containment === "window" ) {
       
   502 			this.containment = [
       
   503 				$( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
       
   504 				$( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
       
   505 				$( window ).scrollLeft() + $( window ).width() -
       
   506 					this.helperProportions.width - this.margins.left,
       
   507 				$( window ).scrollTop() +
       
   508 					( $( window ).height() || document.body.parentNode.scrollHeight ) -
       
   509 					this.helperProportions.height - this.margins.top
       
   510 			];
       
   511 			return;
       
   512 		}
       
   513 
       
   514 		if ( o.containment === "document" ) {
       
   515 			this.containment = [
       
   516 				0,
       
   517 				0,
       
   518 				$( document ).width() - this.helperProportions.width - this.margins.left,
       
   519 				( $( document ).height() || document.body.parentNode.scrollHeight ) -
       
   520 					this.helperProportions.height - this.margins.top
       
   521 			];
       
   522 			return;
       
   523 		}
       
   524 
       
   525 		if ( o.containment.constructor === Array ) {
       
   526 			this.containment = o.containment;
       
   527 			return;
       
   528 		}
       
   529 
       
   530 		if ( o.containment === "parent" ) {
       
   531 			o.containment = this.helper[ 0 ].parentNode;
       
   532 		}
       
   533 
       
   534 		c = $( o.containment );
       
   535 		ce = c[ 0 ];
       
   536 
       
   537 		if ( !ce ) {
       
   538 			return;
       
   539 		}
       
   540 
       
   541 		isUserScrollable = /(scroll|auto)/.test( c.css( "overflow" ) );
       
   542 
       
   543 		this.containment = [
       
   544 			( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) +
       
   545 				( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
       
   546 			( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) +
       
   547 				( parseInt( c.css( "paddingTop" ), 10 ) || 0 ),
       
   548 			( isUserScrollable ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
       
   549 				( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) -
       
   550 				( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) -
       
   551 				this.helperProportions.width -
       
   552 				this.margins.left -
       
   553 				this.margins.right,
       
   554 			( isUserScrollable ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
       
   555 				( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) -
       
   556 				( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) -
       
   557 				this.helperProportions.height -
       
   558 				this.margins.top -
       
   559 				this.margins.bottom
       
   560 		];
       
   561 		this.relativeContainer = c;
       
   562 	},
       
   563 
       
   564 	_convertPositionTo: function( d, pos ) {
       
   565 
       
   566 		if ( !pos ) {
       
   567 			pos = this.position;
       
   568 		}
       
   569 
       
   570 		var mod = d === "absolute" ? 1 : -1,
       
   571 			scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
       
   572 
       
   573 		return {
       
   574 			top: (
       
   575 
       
   576 				// The absolute mouse position
       
   577 				pos.top	+
       
   578 
       
   579 				// Only for relative positioned nodes: Relative offset from element to offset parent
       
   580 				this.offset.relative.top * mod +
       
   581 
       
   582 				// The offsetParent's offset without borders (offset + border)
       
   583 				this.offset.parent.top * mod -
       
   584 				( ( this.cssPosition === "fixed" ?
       
   585 					-this.offset.scroll.top :
       
   586 					( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod )
       
   587 			),
       
   588 			left: (
       
   589 
       
   590 				// The absolute mouse position
       
   591 				pos.left +
       
   592 
       
   593 				// Only for relative positioned nodes: Relative offset from element to offset parent
       
   594 				this.offset.relative.left * mod +
       
   595 
       
   596 				// The offsetParent's offset without borders (offset + border)
       
   597 				this.offset.parent.left * mod	-
       
   598 				( ( this.cssPosition === "fixed" ?
       
   599 					-this.offset.scroll.left :
       
   600 					( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod )
       
   601 			)
       
   602 		};
       
   603 
       
   604 	},
       
   605 
       
   606 	_generatePosition: function( event, constrainPosition ) {
       
   607 
       
   608 		var containment, co, top, left,
       
   609 			o = this.options,
       
   610 			scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ),
       
   611 			pageX = event.pageX,
       
   612 			pageY = event.pageY;
       
   613 
       
   614 		// Cache the scroll
       
   615 		if ( !scrollIsRootNode || !this.offset.scroll ) {
       
   616 			this.offset.scroll = {
       
   617 				top: this.scrollParent.scrollTop(),
       
   618 				left: this.scrollParent.scrollLeft()
       
   619 			};
       
   620 		}
       
   621 
       
   622 		/*
       
   623 		 * - Position constraining -
       
   624 		 * Constrain the position to a mix of grid, containment.
       
   625 		 */
       
   626 
       
   627 		// If we are not dragging yet, we won't check for options
       
   628 		if ( constrainPosition ) {
       
   629 			if ( this.containment ) {
       
   630 				if ( this.relativeContainer ) {
       
   631 					co = this.relativeContainer.offset();
       
   632 					containment = [
       
   633 						this.containment[ 0 ] + co.left,
       
   634 						this.containment[ 1 ] + co.top,
       
   635 						this.containment[ 2 ] + co.left,
       
   636 						this.containment[ 3 ] + co.top
       
   637 					];
       
   638 				} else {
       
   639 					containment = this.containment;
       
   640 				}
       
   641 
       
   642 				if ( event.pageX - this.offset.click.left < containment[ 0 ] ) {
       
   643 					pageX = containment[ 0 ] + this.offset.click.left;
       
   644 				}
       
   645 				if ( event.pageY - this.offset.click.top < containment[ 1 ] ) {
       
   646 					pageY = containment[ 1 ] + this.offset.click.top;
       
   647 				}
       
   648 				if ( event.pageX - this.offset.click.left > containment[ 2 ] ) {
       
   649 					pageX = containment[ 2 ] + this.offset.click.left;
       
   650 				}
       
   651 				if ( event.pageY - this.offset.click.top > containment[ 3 ] ) {
       
   652 					pageY = containment[ 3 ] + this.offset.click.top;
       
   653 				}
       
   654 			}
       
   655 
       
   656 			if ( o.grid ) {
       
   657 
       
   658 				//Check for grid elements set to 0 to prevent divide by 0 error causing invalid
       
   659 				// argument errors in IE (see ticket #6950)
       
   660 				top = o.grid[ 1 ] ? this.originalPageY + Math.round( ( pageY -
       
   661 					this.originalPageY ) / o.grid[ 1 ] ) * o.grid[ 1 ] : this.originalPageY;
       
   662 				pageY = containment ? ( ( top - this.offset.click.top >= containment[ 1 ] ||
       
   663 					top - this.offset.click.top > containment[ 3 ] ) ?
       
   664 						top :
       
   665 						( ( top - this.offset.click.top >= containment[ 1 ] ) ?
       
   666 							top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) : top;
       
   667 
       
   668 				left = o.grid[ 0 ] ? this.originalPageX +
       
   669 					Math.round( ( pageX - this.originalPageX ) / o.grid[ 0 ] ) * o.grid[ 0 ] :
       
   670 					this.originalPageX;
       
   671 				pageX = containment ? ( ( left - this.offset.click.left >= containment[ 0 ] ||
       
   672 					left - this.offset.click.left > containment[ 2 ] ) ?
       
   673 						left :
       
   674 						( ( left - this.offset.click.left >= containment[ 0 ] ) ?
       
   675 							left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) : left;
       
   676 			}
       
   677 
       
   678 			if ( o.axis === "y" ) {
       
   679 				pageX = this.originalPageX;
       
   680 			}
       
   681 
       
   682 			if ( o.axis === "x" ) {
       
   683 				pageY = this.originalPageY;
       
   684 			}
       
   685 		}
       
   686 
       
   687 		return {
       
   688 			top: (
       
   689 
       
   690 				// The absolute mouse position
       
   691 				pageY -
       
   692 
       
   693 				// Click offset (relative to the element)
       
   694 				this.offset.click.top -
       
   695 
       
   696 				// Only for relative positioned nodes: Relative offset from element to offset parent
       
   697 				this.offset.relative.top -
       
   698 
       
   699 				// The offsetParent's offset without borders (offset + border)
       
   700 				this.offset.parent.top +
       
   701 				( this.cssPosition === "fixed" ?
       
   702 					-this.offset.scroll.top :
       
   703 					( scrollIsRootNode ? 0 : this.offset.scroll.top ) )
       
   704 			),
       
   705 			left: (
       
   706 
       
   707 				// The absolute mouse position
       
   708 				pageX -
       
   709 
       
   710 				// Click offset (relative to the element)
       
   711 				this.offset.click.left -
       
   712 
       
   713 				// Only for relative positioned nodes: Relative offset from element to offset parent
       
   714 				this.offset.relative.left -
       
   715 
       
   716 				// The offsetParent's offset without borders (offset + border)
       
   717 				this.offset.parent.left +
       
   718 				( this.cssPosition === "fixed" ?
       
   719 					-this.offset.scroll.left :
       
   720 					( scrollIsRootNode ? 0 : this.offset.scroll.left ) )
       
   721 			)
       
   722 		};
       
   723 
       
   724 	},
       
   725 
       
   726 	_clear: function() {
       
   727 		this._removeClass( this.helper, "ui-draggable-dragging" );
       
   728 		if ( this.helper[ 0 ] !== this.element[ 0 ] && !this.cancelHelperRemoval ) {
       
   729 			this.helper.remove();
       
   730 		}
       
   731 		this.helper = null;
       
   732 		this.cancelHelperRemoval = false;
       
   733 		if ( this.destroyOnClear ) {
       
   734 			this.destroy();
       
   735 		}
       
   736 	},
       
   737 
       
   738 	// From now on bulk stuff - mainly helpers
       
   739 
       
   740 	_trigger: function( type, event, ui ) {
       
   741 		ui = ui || this._uiHash();
       
   742 		$.ui.plugin.call( this, type, [ event, ui, this ], true );
       
   743 
       
   744 		// Absolute position and offset (see #6884 ) have to be recalculated after plugins
       
   745 		if ( /^(drag|start|stop)/.test( type ) ) {
       
   746 			this.positionAbs = this._convertPositionTo( "absolute" );
       
   747 			ui.offset = this.positionAbs;
       
   748 		}
       
   749 		return $.Widget.prototype._trigger.call( this, type, event, ui );
       
   750 	},
       
   751 
       
   752 	plugins: {},
       
   753 
       
   754 	_uiHash: function() {
       
   755 		return {
       
   756 			helper: this.helper,
       
   757 			position: this.position,
       
   758 			originalPosition: this.originalPosition,
       
   759 			offset: this.positionAbs
       
   760 		};
       
   761 	}
       
   762 
       
   763 } );
       
   764 
       
   765 $.ui.plugin.add( "draggable", "connectToSortable", {
       
   766 	start: function( event, ui, draggable ) {
       
   767 		var uiSortable = $.extend( {}, ui, {
       
   768 			item: draggable.element
       
   769 		} );
       
   770 
       
   771 		draggable.sortables = [];
       
   772 		$( draggable.options.connectToSortable ).each( function() {
       
   773 			var sortable = $( this ).sortable( "instance" );
       
   774 
       
   775 			if ( sortable && !sortable.options.disabled ) {
       
   776 				draggable.sortables.push( sortable );
       
   777 
       
   778 				// RefreshPositions is called at drag start to refresh the containerCache
       
   779 				// which is used in drag. This ensures it's initialized and synchronized
       
   780 				// with any changes that might have happened on the page since initialization.
       
   781 				sortable.refreshPositions();
       
   782 				sortable._trigger( "activate", event, uiSortable );
       
   783 			}
       
   784 		} );
       
   785 	},
       
   786 	stop: function( event, ui, draggable ) {
       
   787 		var uiSortable = $.extend( {}, ui, {
       
   788 			item: draggable.element
       
   789 		} );
       
   790 
       
   791 		draggable.cancelHelperRemoval = false;
       
   792 
       
   793 		$.each( draggable.sortables, function() {
       
   794 			var sortable = this;
       
   795 
       
   796 			if ( sortable.isOver ) {
       
   797 				sortable.isOver = 0;
       
   798 
       
   799 				// Allow this sortable to handle removing the helper
       
   800 				draggable.cancelHelperRemoval = true;
       
   801 				sortable.cancelHelperRemoval = false;
       
   802 
       
   803 				// Use _storedCSS To restore properties in the sortable,
       
   804 				// as this also handles revert (#9675) since the draggable
       
   805 				// may have modified them in unexpected ways (#8809)
       
   806 				sortable._storedCSS = {
       
   807 					position: sortable.placeholder.css( "position" ),
       
   808 					top: sortable.placeholder.css( "top" ),
       
   809 					left: sortable.placeholder.css( "left" )
       
   810 				};
       
   811 
       
   812 				sortable._mouseStop( event );
       
   813 
       
   814 				// Once drag has ended, the sortable should return to using
       
   815 				// its original helper, not the shared helper from draggable
       
   816 				sortable.options.helper = sortable.options._helper;
       
   817 			} else {
       
   818 
       
   819 				// Prevent this Sortable from removing the helper.
       
   820 				// However, don't set the draggable to remove the helper
       
   821 				// either as another connected Sortable may yet handle the removal.
       
   822 				sortable.cancelHelperRemoval = true;
       
   823 
       
   824 				sortable._trigger( "deactivate", event, uiSortable );
       
   825 			}
       
   826 		} );
       
   827 	},
       
   828 	drag: function( event, ui, draggable ) {
       
   829 		$.each( draggable.sortables, function() {
       
   830 			var innermostIntersecting = false,
       
   831 				sortable = this;
       
   832 
       
   833 			// Copy over variables that sortable's _intersectsWith uses
       
   834 			sortable.positionAbs = draggable.positionAbs;
       
   835 			sortable.helperProportions = draggable.helperProportions;
       
   836 			sortable.offset.click = draggable.offset.click;
       
   837 
       
   838 			if ( sortable._intersectsWith( sortable.containerCache ) ) {
       
   839 				innermostIntersecting = true;
       
   840 
       
   841 				$.each( draggable.sortables, function() {
       
   842 
       
   843 					// Copy over variables that sortable's _intersectsWith uses
       
   844 					this.positionAbs = draggable.positionAbs;
       
   845 					this.helperProportions = draggable.helperProportions;
       
   846 					this.offset.click = draggable.offset.click;
       
   847 
       
   848 					if ( this !== sortable &&
       
   849 							this._intersectsWith( this.containerCache ) &&
       
   850 							$.contains( sortable.element[ 0 ], this.element[ 0 ] ) ) {
       
   851 						innermostIntersecting = false;
       
   852 					}
       
   853 
       
   854 					return innermostIntersecting;
       
   855 				} );
       
   856 			}
       
   857 
       
   858 			if ( innermostIntersecting ) {
       
   859 
       
   860 				// If it intersects, we use a little isOver variable and set it once,
       
   861 				// so that the move-in stuff gets fired only once.
       
   862 				if ( !sortable.isOver ) {
       
   863 					sortable.isOver = 1;
       
   864 
       
   865 					// Store draggable's parent in case we need to reappend to it later.
       
   866 					draggable._parent = ui.helper.parent();
       
   867 
       
   868 					sortable.currentItem = ui.helper
       
   869 						.appendTo( sortable.element )
       
   870 						.data( "ui-sortable-item", true );
       
   871 
       
   872 					// Store helper option to later restore it
       
   873 					sortable.options._helper = sortable.options.helper;
       
   874 
       
   875 					sortable.options.helper = function() {
       
   876 						return ui.helper[ 0 ];
       
   877 					};
       
   878 
       
   879 					// Fire the start events of the sortable with our passed browser event,
       
   880 					// and our own helper (so it doesn't create a new one)
       
   881 					event.target = sortable.currentItem[ 0 ];
       
   882 					sortable._mouseCapture( event, true );
       
   883 					sortable._mouseStart( event, true, true );
       
   884 
       
   885 					// Because the browser event is way off the new appended portlet,
       
   886 					// modify necessary variables to reflect the changes
       
   887 					sortable.offset.click.top = draggable.offset.click.top;
       
   888 					sortable.offset.click.left = draggable.offset.click.left;
       
   889 					sortable.offset.parent.left -= draggable.offset.parent.left -
       
   890 						sortable.offset.parent.left;
       
   891 					sortable.offset.parent.top -= draggable.offset.parent.top -
       
   892 						sortable.offset.parent.top;
       
   893 
       
   894 					draggable._trigger( "toSortable", event );
       
   895 
       
   896 					// Inform draggable that the helper is in a valid drop zone,
       
   897 					// used solely in the revert option to handle "valid/invalid".
       
   898 					draggable.dropped = sortable.element;
       
   899 
       
   900 					// Need to refreshPositions of all sortables in the case that
       
   901 					// adding to one sortable changes the location of the other sortables (#9675)
       
   902 					$.each( draggable.sortables, function() {
       
   903 						this.refreshPositions();
       
   904 					} );
       
   905 
       
   906 					// Hack so receive/update callbacks work (mostly)
       
   907 					draggable.currentItem = draggable.element;
       
   908 					sortable.fromOutside = draggable;
       
   909 				}
       
   910 
       
   911 				if ( sortable.currentItem ) {
       
   912 					sortable._mouseDrag( event );
       
   913 
       
   914 					// Copy the sortable's position because the draggable's can potentially reflect
       
   915 					// a relative position, while sortable is always absolute, which the dragged
       
   916 					// element has now become. (#8809)
       
   917 					ui.position = sortable.position;
       
   918 				}
       
   919 			} else {
       
   920 
       
   921 				// If it doesn't intersect with the sortable, and it intersected before,
       
   922 				// we fake the drag stop of the sortable, but make sure it doesn't remove
       
   923 				// the helper by using cancelHelperRemoval.
       
   924 				if ( sortable.isOver ) {
       
   925 
       
   926 					sortable.isOver = 0;
       
   927 					sortable.cancelHelperRemoval = true;
       
   928 
       
   929 					// Calling sortable's mouseStop would trigger a revert,
       
   930 					// so revert must be temporarily false until after mouseStop is called.
       
   931 					sortable.options._revert = sortable.options.revert;
       
   932 					sortable.options.revert = false;
       
   933 
       
   934 					sortable._trigger( "out", event, sortable._uiHash( sortable ) );
       
   935 					sortable._mouseStop( event, true );
       
   936 
       
   937 					// Restore sortable behaviors that were modfied
       
   938 					// when the draggable entered the sortable area (#9481)
       
   939 					sortable.options.revert = sortable.options._revert;
       
   940 					sortable.options.helper = sortable.options._helper;
       
   941 
       
   942 					if ( sortable.placeholder ) {
       
   943 						sortable.placeholder.remove();
       
   944 					}
       
   945 
       
   946 					// Restore and recalculate the draggable's offset considering the sortable
       
   947 					// may have modified them in unexpected ways. (#8809, #10669)
       
   948 					ui.helper.appendTo( draggable._parent );
       
   949 					draggable._refreshOffsets( event );
       
   950 					ui.position = draggable._generatePosition( event, true );
       
   951 
       
   952 					draggable._trigger( "fromSortable", event );
       
   953 
       
   954 					// Inform draggable that the helper is no longer in a valid drop zone
       
   955 					draggable.dropped = false;
       
   956 
       
   957 					// Need to refreshPositions of all sortables just in case removing
       
   958 					// from one sortable changes the location of other sortables (#9675)
       
   959 					$.each( draggable.sortables, function() {
       
   960 						this.refreshPositions();
       
   961 					} );
       
   962 				}
       
   963 			}
       
   964 		} );
       
   965 	}
       
   966 } );
       
   967 
       
   968 $.ui.plugin.add( "draggable", "cursor", {
       
   969 	start: function( event, ui, instance ) {
       
   970 		var t = $( "body" ),
       
   971 			o = instance.options;
       
   972 
       
   973 		if ( t.css( "cursor" ) ) {
       
   974 			o._cursor = t.css( "cursor" );
       
   975 		}
       
   976 		t.css( "cursor", o.cursor );
       
   977 	},
       
   978 	stop: function( event, ui, instance ) {
       
   979 		var o = instance.options;
       
   980 		if ( o._cursor ) {
       
   981 			$( "body" ).css( "cursor", o._cursor );
       
   982 		}
       
   983 	}
       
   984 } );
       
   985 
       
   986 $.ui.plugin.add( "draggable", "opacity", {
       
   987 	start: function( event, ui, instance ) {
       
   988 		var t = $( ui.helper ),
       
   989 			o = instance.options;
       
   990 		if ( t.css( "opacity" ) ) {
       
   991 			o._opacity = t.css( "opacity" );
       
   992 		}
       
   993 		t.css( "opacity", o.opacity );
       
   994 	},
       
   995 	stop: function( event, ui, instance ) {
       
   996 		var o = instance.options;
       
   997 		if ( o._opacity ) {
       
   998 			$( ui.helper ).css( "opacity", o._opacity );
       
   999 		}
       
  1000 	}
       
  1001 } );
       
  1002 
       
  1003 $.ui.plugin.add( "draggable", "scroll", {
       
  1004 	start: function( event, ui, i ) {
       
  1005 		if ( !i.scrollParentNotHidden ) {
       
  1006 			i.scrollParentNotHidden = i.helper.scrollParent( false );
       
  1007 		}
       
  1008 
       
  1009 		if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] &&
       
  1010 				i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) {
       
  1011 			i.overflowOffset = i.scrollParentNotHidden.offset();
       
  1012 		}
       
  1013 	},
       
  1014 	drag: function( event, ui, i  ) {
       
  1015 
       
  1016 		var o = i.options,
       
  1017 			scrolled = false,
       
  1018 			scrollParent = i.scrollParentNotHidden[ 0 ],
       
  1019 			document = i.document[ 0 ];
       
  1020 
       
  1021 		if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) {
       
  1022 			if ( !o.axis || o.axis !== "x" ) {
       
  1023 				if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY <
       
  1024 						o.scrollSensitivity ) {
       
  1025 					scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed;
       
  1026 				} else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) {
       
  1027 					scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed;
       
  1028 				}
       
  1029 			}
       
  1030 
       
  1031 			if ( !o.axis || o.axis !== "y" ) {
       
  1032 				if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX <
       
  1033 						o.scrollSensitivity ) {
       
  1034 					scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed;
       
  1035 				} else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) {
       
  1036 					scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed;
       
  1037 				}
       
  1038 			}
       
  1039 
       
  1040 		} else {
       
  1041 
       
  1042 			if ( !o.axis || o.axis !== "x" ) {
       
  1043 				if ( event.pageY - $( document ).scrollTop() < o.scrollSensitivity ) {
       
  1044 					scrolled = $( document ).scrollTop( $( document ).scrollTop() - o.scrollSpeed );
       
  1045 				} else if ( $( window ).height() - ( event.pageY - $( document ).scrollTop() ) <
       
  1046 						o.scrollSensitivity ) {
       
  1047 					scrolled = $( document ).scrollTop( $( document ).scrollTop() + o.scrollSpeed );
       
  1048 				}
       
  1049 			}
       
  1050 
       
  1051 			if ( !o.axis || o.axis !== "y" ) {
       
  1052 				if ( event.pageX - $( document ).scrollLeft() < o.scrollSensitivity ) {
       
  1053 					scrolled = $( document ).scrollLeft(
       
  1054 						$( document ).scrollLeft() - o.scrollSpeed
       
  1055 					);
       
  1056 				} else if ( $( window ).width() - ( event.pageX - $( document ).scrollLeft() ) <
       
  1057 						o.scrollSensitivity ) {
       
  1058 					scrolled = $( document ).scrollLeft(
       
  1059 						$( document ).scrollLeft() + o.scrollSpeed
       
  1060 					);
       
  1061 				}
       
  1062 			}
       
  1063 
       
  1064 		}
       
  1065 
       
  1066 		if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) {
       
  1067 			$.ui.ddmanager.prepareOffsets( i, event );
       
  1068 		}
       
  1069 
       
  1070 	}
       
  1071 } );
       
  1072 
       
  1073 $.ui.plugin.add( "draggable", "snap", {
       
  1074 	start: function( event, ui, i ) {
       
  1075 
       
  1076 		var o = i.options;
       
  1077 
       
  1078 		i.snapElements = [];
       
  1079 
       
  1080 		$( o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap )
       
  1081 			.each( function() {
       
  1082 				var $t = $( this ),
       
  1083 					$o = $t.offset();
       
  1084 				if ( this !== i.element[ 0 ] ) {
       
  1085 					i.snapElements.push( {
       
  1086 						item: this,
       
  1087 						width: $t.outerWidth(), height: $t.outerHeight(),
       
  1088 						top: $o.top, left: $o.left
       
  1089 					} );
       
  1090 				}
       
  1091 			} );
       
  1092 
       
  1093 	},
       
  1094 	drag: function( event, ui, inst ) {
       
  1095 
       
  1096 		var ts, bs, ls, rs, l, r, t, b, i, first,
       
  1097 			o = inst.options,
       
  1098 			d = o.snapTolerance,
       
  1099 			x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
       
  1100 			y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
       
  1101 
       
  1102 		for ( i = inst.snapElements.length - 1; i >= 0; i-- ) {
       
  1103 
       
  1104 			l = inst.snapElements[ i ].left - inst.margins.left;
       
  1105 			r = l + inst.snapElements[ i ].width;
       
  1106 			t = inst.snapElements[ i ].top - inst.margins.top;
       
  1107 			b = t + inst.snapElements[ i ].height;
       
  1108 
       
  1109 			if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d ||
       
  1110 					!$.contains( inst.snapElements[ i ].item.ownerDocument,
       
  1111 					inst.snapElements[ i ].item ) ) {
       
  1112 				if ( inst.snapElements[ i ].snapping ) {
       
  1113 					( inst.options.snap.release &&
       
  1114 						inst.options.snap.release.call(
       
  1115 							inst.element,
       
  1116 							event,
       
  1117 							$.extend( inst._uiHash(), { snapItem: inst.snapElements[ i ].item } )
       
  1118 						) );
       
  1119 				}
       
  1120 				inst.snapElements[ i ].snapping = false;
       
  1121 				continue;
       
  1122 			}
       
  1123 
       
  1124 			if ( o.snapMode !== "inner" ) {
       
  1125 				ts = Math.abs( t - y2 ) <= d;
       
  1126 				bs = Math.abs( b - y1 ) <= d;
       
  1127 				ls = Math.abs( l - x2 ) <= d;
       
  1128 				rs = Math.abs( r - x1 ) <= d;
       
  1129 				if ( ts ) {
       
  1130 					ui.position.top = inst._convertPositionTo( "relative", {
       
  1131 						top: t - inst.helperProportions.height,
       
  1132 						left: 0
       
  1133 					} ).top;
       
  1134 				}
       
  1135 				if ( bs ) {
       
  1136 					ui.position.top = inst._convertPositionTo( "relative", {
       
  1137 						top: b,
       
  1138 						left: 0
       
  1139 					} ).top;
       
  1140 				}
       
  1141 				if ( ls ) {
       
  1142 					ui.position.left = inst._convertPositionTo( "relative", {
       
  1143 						top: 0,
       
  1144 						left: l - inst.helperProportions.width
       
  1145 					} ).left;
       
  1146 				}
       
  1147 				if ( rs ) {
       
  1148 					ui.position.left = inst._convertPositionTo( "relative", {
       
  1149 						top: 0,
       
  1150 						left: r
       
  1151 					} ).left;
       
  1152 				}
       
  1153 			}
       
  1154 
       
  1155 			first = ( ts || bs || ls || rs );
       
  1156 
       
  1157 			if ( o.snapMode !== "outer" ) {
       
  1158 				ts = Math.abs( t - y1 ) <= d;
       
  1159 				bs = Math.abs( b - y2 ) <= d;
       
  1160 				ls = Math.abs( l - x1 ) <= d;
       
  1161 				rs = Math.abs( r - x2 ) <= d;
       
  1162 				if ( ts ) {
       
  1163 					ui.position.top = inst._convertPositionTo( "relative", {
       
  1164 						top: t,
       
  1165 						left: 0
       
  1166 					} ).top;
       
  1167 				}
       
  1168 				if ( bs ) {
       
  1169 					ui.position.top = inst._convertPositionTo( "relative", {
       
  1170 						top: b - inst.helperProportions.height,
       
  1171 						left: 0
       
  1172 					} ).top;
       
  1173 				}
       
  1174 				if ( ls ) {
       
  1175 					ui.position.left = inst._convertPositionTo( "relative", {
       
  1176 						top: 0,
       
  1177 						left: l
       
  1178 					} ).left;
       
  1179 				}
       
  1180 				if ( rs ) {
       
  1181 					ui.position.left = inst._convertPositionTo( "relative", {
       
  1182 						top: 0,
       
  1183 						left: r - inst.helperProportions.width
       
  1184 					} ).left;
       
  1185 				}
       
  1186 			}
       
  1187 
       
  1188 			if ( !inst.snapElements[ i ].snapping && ( ts || bs || ls || rs || first ) ) {
       
  1189 				( inst.options.snap.snap &&
       
  1190 					inst.options.snap.snap.call(
       
  1191 						inst.element,
       
  1192 						event,
       
  1193 						$.extend( inst._uiHash(), {
       
  1194 							snapItem: inst.snapElements[ i ].item
       
  1195 						} ) ) );
       
  1196 			}
       
  1197 			inst.snapElements[ i ].snapping = ( ts || bs || ls || rs || first );
       
  1198 
       
  1199 		}
       
  1200 
       
  1201 	}
       
  1202 } );
       
  1203 
       
  1204 $.ui.plugin.add( "draggable", "stack", {
       
  1205 	start: function( event, ui, instance ) {
       
  1206 		var min,
       
  1207 			o = instance.options,
       
  1208 			group = $.makeArray( $( o.stack ) ).sort( function( a, b ) {
       
  1209 				return ( parseInt( $( a ).css( "zIndex" ), 10 ) || 0 ) -
       
  1210 					( parseInt( $( b ).css( "zIndex" ), 10 ) || 0 );
       
  1211 			} );
       
  1212 
       
  1213 		if ( !group.length ) { return; }
       
  1214 
       
  1215 		min = parseInt( $( group[ 0 ] ).css( "zIndex" ), 10 ) || 0;
       
  1216 		$( group ).each( function( i ) {
       
  1217 			$( this ).css( "zIndex", min + i );
       
  1218 		} );
       
  1219 		this.css( "zIndex", ( min + group.length ) );
       
  1220 	}
       
  1221 } );
       
  1222 
       
  1223 $.ui.plugin.add( "draggable", "zIndex", {
       
  1224 	start: function( event, ui, instance ) {
       
  1225 		var t = $( ui.helper ),
       
  1226 			o = instance.options;
       
  1227 
       
  1228 		if ( t.css( "zIndex" ) ) {
       
  1229 			o._zIndex = t.css( "zIndex" );
       
  1230 		}
       
  1231 		t.css( "zIndex", o.zIndex );
       
  1232 	},
       
  1233 	stop: function( event, ui, instance ) {
       
  1234 		var o = instance.options;
       
  1235 
       
  1236 		if ( o._zIndex ) {
       
  1237 			$( ui.helper ).css( "zIndex", o._zIndex );
       
  1238 		}
       
  1239 	}
       
  1240 } );
       
  1241 
       
  1242 return $.ui.draggable;
       
  1243 
       
  1244 } ) );