openrat-cms

# OpenRat Content Management System
git clone http://git.code.weiherhei.de/openrat-cms.git
Log | Files | Refs

jquery-ui.js (122889B)


      1 /*! jQuery UI - v1.12.1 - 2018-09-03
      2 * http://jqueryui.com
      3 * Includes: widget.js, data.js, scroll-parent.js, widgets/draggable.js, widgets/droppable.js, widgets/sortable.js, widgets/mouse.js
      4 * Copyright jQuery Foundation and other contributors; Licensed MIT */
      5 
      6 (function( factory ) {
      7 	if ( typeof define === "function" && define.amd ) {
      8 
      9 		// AMD. Register as an anonymous module.
     10 		define([ "jquery" ], factory );
     11 	} else {
     12 
     13 		// Browser globals
     14 		factory( jQuery );
     15 	}
     16 }(function( $ ) {
     17 
     18 $.ui = $.ui || {};
     19 
     20 var version = $.ui.version = "1.12.1";
     21 
     22 
     23 /*!
     24  * jQuery UI Widget 1.12.1
     25  * http://jqueryui.com
     26  *
     27  * Copyright jQuery Foundation and other contributors
     28  * Released under the MIT license.
     29  * http://jquery.org/license
     30  */
     31 
     32 //>>label: Widget
     33 //>>group: Core
     34 //>>description: Provides a factory for creating stateful widgets with a common API.
     35 //>>docs: http://api.jqueryui.com/jQuery.widget/
     36 //>>demos: http://jqueryui.com/widget/
     37 
     38 
     39 
     40 var widgetUuid = 0;
     41 var widgetSlice = Array.prototype.slice;
     42 
     43 $.cleanData = ( function( orig ) {
     44 	return function( elems ) {
     45 		var events, elem, i;
     46 		for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) {
     47 			try {
     48 
     49 				// Only trigger remove when necessary to save time
     50 				events = $._data( elem, "events" );
     51 				if ( events && events.remove ) {
     52 					$( elem ).triggerHandler( "remove" );
     53 				}
     54 
     55 			// Http://bugs.jquery.com/ticket/8235
     56 			} catch ( e ) {}
     57 		}
     58 		orig( elems );
     59 	};
     60 } )( $.cleanData );
     61 
     62 $.widget = function( name, base, prototype ) {
     63 	var existingConstructor, constructor, basePrototype;
     64 
     65 	// ProxiedPrototype allows the provided prototype to remain unmodified
     66 	// so that it can be used as a mixin for multiple widgets (#8876)
     67 	var proxiedPrototype = {};
     68 
     69 	var namespace = name.split( "." )[ 0 ];
     70 	name = name.split( "." )[ 1 ];
     71 	var fullName = namespace + "-" + name;
     72 
     73 	if ( !prototype ) {
     74 		prototype = base;
     75 		base = $.Widget;
     76 	}
     77 
     78 	if ( $.isArray( prototype ) ) {
     79 		prototype = $.extend.apply( null, [ {} ].concat( prototype ) );
     80 	}
     81 
     82 	// Create selector for plugin
     83 	$.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
     84 		return !!$.data( elem, fullName );
     85 	};
     86 
     87 	$[ namespace ] = $[ namespace ] || {};
     88 	existingConstructor = $[ namespace ][ name ];
     89 	constructor = $[ namespace ][ name ] = function( options, element ) {
     90 
     91 		// Allow instantiation without "new" keyword
     92 		if ( !this._createWidget ) {
     93 			return new constructor( options, element );
     94 		}
     95 
     96 		// Allow instantiation without initializing for simple inheritance
     97 		// must use "new" keyword (the code above always passes args)
     98 		if ( arguments.length ) {
     99 			this._createWidget( options, element );
    100 		}
    101 	};
    102 
    103 	// Extend with the existing constructor to carry over any static properties
    104 	$.extend( constructor, existingConstructor, {
    105 		version: prototype.version,
    106 
    107 		// Copy the object used to create the prototype in case we need to
    108 		// redefine the widget later
    109 		_proto: $.extend( {}, prototype ),
    110 
    111 		// Track widgets that inherit from this widget in case this widget is
    112 		// redefined after a widget inherits from it
    113 		_childConstructors: []
    114 	} );
    115 
    116 	basePrototype = new base();
    117 
    118 	// We need to make the options hash a property directly on the new instance
    119 	// otherwise we'll modify the options hash on the prototype that we're
    120 	// inheriting from
    121 	basePrototype.options = $.widget.extend( {}, basePrototype.options );
    122 	$.each( prototype, function( prop, value ) {
    123 		if ( !$.isFunction( value ) ) {
    124 			proxiedPrototype[ prop ] = value;
    125 			return;
    126 		}
    127 		proxiedPrototype[ prop ] = ( function() {
    128 			function _super() {
    129 				return base.prototype[ prop ].apply( this, arguments );
    130 			}
    131 
    132 			function _superApply( args ) {
    133 				return base.prototype[ prop ].apply( this, args );
    134 			}
    135 
    136 			return function() {
    137 				var __super = this._super;
    138 				var __superApply = this._superApply;
    139 				var returnValue;
    140 
    141 				this._super = _super;
    142 				this._superApply = _superApply;
    143 
    144 				returnValue = value.apply( this, arguments );
    145 
    146 				this._super = __super;
    147 				this._superApply = __superApply;
    148 
    149 				return returnValue;
    150 			};
    151 		} )();
    152 	} );
    153 	constructor.prototype = $.widget.extend( basePrototype, {
    154 
    155 		// TODO: remove support for widgetEventPrefix
    156 		// always use the name + a colon as the prefix, e.g., draggable:start
    157 		// don't prefix for widgets that aren't DOM-based
    158 		widgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name
    159 	}, proxiedPrototype, {
    160 		constructor: constructor,
    161 		namespace: namespace,
    162 		widgetName: name,
    163 		widgetFullName: fullName
    164 	} );
    165 
    166 	// If this widget is being redefined then we need to find all widgets that
    167 	// are inheriting from it and redefine all of them so that they inherit from
    168 	// the new version of this widget. We're essentially trying to replace one
    169 	// level in the prototype chain.
    170 	if ( existingConstructor ) {
    171 		$.each( existingConstructor._childConstructors, function( i, child ) {
    172 			var childPrototype = child.prototype;
    173 
    174 			// Redefine the child widget using the same prototype that was
    175 			// originally used, but inherit from the new version of the base
    176 			$.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor,
    177 				child._proto );
    178 		} );
    179 
    180 		// Remove the list of existing child constructors from the old constructor
    181 		// so the old child constructors can be garbage collected
    182 		delete existingConstructor._childConstructors;
    183 	} else {
    184 		base._childConstructors.push( constructor );
    185 	}
    186 
    187 	$.widget.bridge( name, constructor );
    188 
    189 	return constructor;
    190 };
    191 
    192 $.widget.extend = function( target ) {
    193 	var input = widgetSlice.call( arguments, 1 );
    194 	var inputIndex = 0;
    195 	var inputLength = input.length;
    196 	var key;
    197 	var value;
    198 
    199 	for ( ; inputIndex < inputLength; inputIndex++ ) {
    200 		for ( key in input[ inputIndex ] ) {
    201 			value = input[ inputIndex ][ key ];
    202 			if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
    203 
    204 				// Clone objects
    205 				if ( $.isPlainObject( value ) ) {
    206 					target[ key ] = $.isPlainObject( target[ key ] ) ?
    207 						$.widget.extend( {}, target[ key ], value ) :
    208 
    209 						// Don't extend strings, arrays, etc. with objects
    210 						$.widget.extend( {}, value );
    211 
    212 				// Copy everything else by reference
    213 				} else {
    214 					target[ key ] = value;
    215 				}
    216 			}
    217 		}
    218 	}
    219 	return target;
    220 };
    221 
    222 $.widget.bridge = function( name, object ) {
    223 	var fullName = object.prototype.widgetFullName || name;
    224 	$.fn[ name ] = function( options ) {
    225 		var isMethodCall = typeof options === "string";
    226 		var args = widgetSlice.call( arguments, 1 );
    227 		var returnValue = this;
    228 
    229 		if ( isMethodCall ) {
    230 
    231 			// If this is an empty collection, we need to have the instance method
    232 			// return undefined instead of the jQuery instance
    233 			if ( !this.length && options === "instance" ) {
    234 				returnValue = undefined;
    235 			} else {
    236 				this.each( function() {
    237 					var methodValue;
    238 					var instance = $.data( this, fullName );
    239 
    240 					if ( options === "instance" ) {
    241 						returnValue = instance;
    242 						return false;
    243 					}
    244 
    245 					if ( !instance ) {
    246 						return $.error( "cannot call methods on " + name +
    247 							" prior to initialization; " +
    248 							"attempted to call method '" + options + "'" );
    249 					}
    250 
    251 					if ( !$.isFunction( instance[ options ] ) || options.charAt( 0 ) === "_" ) {
    252 						return $.error( "no such method '" + options + "' for " + name +
    253 							" widget instance" );
    254 					}
    255 
    256 					methodValue = instance[ options ].apply( instance, args );
    257 
    258 					if ( methodValue !== instance && methodValue !== undefined ) {
    259 						returnValue = methodValue && methodValue.jquery ?
    260 							returnValue.pushStack( methodValue.get() ) :
    261 							methodValue;
    262 						return false;
    263 					}
    264 				} );
    265 			}
    266 		} else {
    267 
    268 			// Allow multiple hashes to be passed on init
    269 			if ( args.length ) {
    270 				options = $.widget.extend.apply( null, [ options ].concat( args ) );
    271 			}
    272 
    273 			this.each( function() {
    274 				var instance = $.data( this, fullName );
    275 				if ( instance ) {
    276 					instance.option( options || {} );
    277 					if ( instance._init ) {
    278 						instance._init();
    279 					}
    280 				} else {
    281 					$.data( this, fullName, new object( options, this ) );
    282 				}
    283 			} );
    284 		}
    285 
    286 		return returnValue;
    287 	};
    288 };
    289 
    290 $.Widget = function( /* options, element */ ) {};
    291 $.Widget._childConstructors = [];
    292 
    293 $.Widget.prototype = {
    294 	widgetName: "widget",
    295 	widgetEventPrefix: "",
    296 	defaultElement: "<div>",
    297 
    298 	options: {
    299 		classes: {},
    300 		disabled: false,
    301 
    302 		// Callbacks
    303 		create: null
    304 	},
    305 
    306 	_createWidget: function( options, element ) {
    307 		element = $( element || this.defaultElement || this )[ 0 ];
    308 		this.element = $( element );
    309 		this.uuid = widgetUuid++;
    310 		this.eventNamespace = "." + this.widgetName + this.uuid;
    311 
    312 		this.bindings = $();
    313 		this.hoverable = $();
    314 		this.focusable = $();
    315 		this.classesElementLookup = {};
    316 
    317 		if ( element !== this ) {
    318 			$.data( element, this.widgetFullName, this );
    319 			this._on( true, this.element, {
    320 				remove: function( event ) {
    321 					if ( event.target === element ) {
    322 						this.destroy();
    323 					}
    324 				}
    325 			} );
    326 			this.document = $( element.style ?
    327 
    328 				// Element within the document
    329 				element.ownerDocument :
    330 
    331 				// Element is window or document
    332 				element.document || element );
    333 			this.window = $( this.document[ 0 ].defaultView || this.document[ 0 ].parentWindow );
    334 		}
    335 
    336 		this.options = $.widget.extend( {},
    337 			this.options,
    338 			this._getCreateOptions(),
    339 			options );
    340 
    341 		this._create();
    342 
    343 		if ( this.options.disabled ) {
    344 			this._setOptionDisabled( this.options.disabled );
    345 		}
    346 
    347 		this._trigger( "create", null, this._getCreateEventData() );
    348 		this._init();
    349 	},
    350 
    351 	_getCreateOptions: function() {
    352 		return {};
    353 	},
    354 
    355 	_getCreateEventData: $.noop,
    356 
    357 	_create: $.noop,
    358 
    359 	_init: $.noop,
    360 
    361 	destroy: function() {
    362 		var that = this;
    363 
    364 		this._destroy();
    365 		$.each( this.classesElementLookup, function( key, value ) {
    366 			that._removeClass( value, key );
    367 		} );
    368 
    369 		// We can probably remove the unbind calls in 2.0
    370 		// all event bindings should go through this._on()
    371 		this.element
    372 			.off( this.eventNamespace )
    373 			.removeData( this.widgetFullName );
    374 		this.widget()
    375 			.off( this.eventNamespace )
    376 			.removeAttr( "aria-disabled" );
    377 
    378 		// Clean up events and states
    379 		this.bindings.off( this.eventNamespace );
    380 	},
    381 
    382 	_destroy: $.noop,
    383 
    384 	widget: function() {
    385 		return this.element;
    386 	},
    387 
    388 	option: function( key, value ) {
    389 		var options = key;
    390 		var parts;
    391 		var curOption;
    392 		var i;
    393 
    394 		if ( arguments.length === 0 ) {
    395 
    396 			// Don't return a reference to the internal hash
    397 			return $.widget.extend( {}, this.options );
    398 		}
    399 
    400 		if ( typeof key === "string" ) {
    401 
    402 			// Handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
    403 			options = {};
    404 			parts = key.split( "." );
    405 			key = parts.shift();
    406 			if ( parts.length ) {
    407 				curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
    408 				for ( i = 0; i < parts.length - 1; i++ ) {
    409 					curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
    410 					curOption = curOption[ parts[ i ] ];
    411 				}
    412 				key = parts.pop();
    413 				if ( arguments.length === 1 ) {
    414 					return curOption[ key ] === undefined ? null : curOption[ key ];
    415 				}
    416 				curOption[ key ] = value;
    417 			} else {
    418 				if ( arguments.length === 1 ) {
    419 					return this.options[ key ] === undefined ? null : this.options[ key ];
    420 				}
    421 				options[ key ] = value;
    422 			}
    423 		}
    424 
    425 		this._setOptions( options );
    426 
    427 		return this;
    428 	},
    429 
    430 	_setOptions: function( options ) {
    431 		var key;
    432 
    433 		for ( key in options ) {
    434 			this._setOption( key, options[ key ] );
    435 		}
    436 
    437 		return this;
    438 	},
    439 
    440 	_setOption: function( key, value ) {
    441 		if ( key === "classes" ) {
    442 			this._setOptionClasses( value );
    443 		}
    444 
    445 		this.options[ key ] = value;
    446 
    447 		if ( key === "disabled" ) {
    448 			this._setOptionDisabled( value );
    449 		}
    450 
    451 		return this;
    452 	},
    453 
    454 	_setOptionClasses: function( value ) {
    455 		var classKey, elements, currentElements;
    456 
    457 		for ( classKey in value ) {
    458 			currentElements = this.classesElementLookup[ classKey ];
    459 			if ( value[ classKey ] === this.options.classes[ classKey ] ||
    460 					!currentElements ||
    461 					!currentElements.length ) {
    462 				continue;
    463 			}
    464 
    465 			// We are doing this to create a new jQuery object because the _removeClass() call
    466 			// on the next line is going to destroy the reference to the current elements being
    467 			// tracked. We need to save a copy of this collection so that we can add the new classes
    468 			// below.
    469 			elements = $( currentElements.get() );
    470 			this._removeClass( currentElements, classKey );
    471 
    472 			// We don't use _addClass() here, because that uses this.options.classes
    473 			// for generating the string of classes. We want to use the value passed in from
    474 			// _setOption(), this is the new value of the classes option which was passed to
    475 			// _setOption(). We pass this value directly to _classes().
    476 			elements.addClass( this._classes( {
    477 				element: elements,
    478 				keys: classKey,
    479 				classes: value,
    480 				add: true
    481 			} ) );
    482 		}
    483 	},
    484 
    485 	_setOptionDisabled: function( value ) {
    486 		this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, !!value );
    487 
    488 		// If the widget is becoming disabled, then nothing is interactive
    489 		if ( value ) {
    490 			this._removeClass( this.hoverable, null, "ui-state-hover" );
    491 			this._removeClass( this.focusable, null, "ui-state-focus" );
    492 		}
    493 	},
    494 
    495 	enable: function() {
    496 		return this._setOptions( { disabled: false } );
    497 	},
    498 
    499 	disable: function() {
    500 		return this._setOptions( { disabled: true } );
    501 	},
    502 
    503 	_classes: function( options ) {
    504 		var full = [];
    505 		var that = this;
    506 
    507 		options = $.extend( {
    508 			element: this.element,
    509 			classes: this.options.classes || {}
    510 		}, options );
    511 
    512 		function processClassString( classes, checkOption ) {
    513 			var current, i;
    514 			for ( i = 0; i < classes.length; i++ ) {
    515 				current = that.classesElementLookup[ classes[ i ] ] || $();
    516 				if ( options.add ) {
    517 					current = $( $.unique( current.get().concat( options.element.get() ) ) );
    518 				} else {
    519 					current = $( current.not( options.element ).get() );
    520 				}
    521 				that.classesElementLookup[ classes[ i ] ] = current;
    522 				full.push( classes[ i ] );
    523 				if ( checkOption && options.classes[ classes[ i ] ] ) {
    524 					full.push( options.classes[ classes[ i ] ] );
    525 				}
    526 			}
    527 		}
    528 
    529 		this._on( options.element, {
    530 			"remove": "_untrackClassesElement"
    531 		} );
    532 
    533 		if ( options.keys ) {
    534 			processClassString( options.keys.match( /\S+/g ) || [], true );
    535 		}
    536 		if ( options.extra ) {
    537 			processClassString( options.extra.match( /\S+/g ) || [] );
    538 		}
    539 
    540 		return full.join( " " );
    541 	},
    542 
    543 	_untrackClassesElement: function( event ) {
    544 		var that = this;
    545 		$.each( that.classesElementLookup, function( key, value ) {
    546 			if ( $.inArray( event.target, value ) !== -1 ) {
    547 				that.classesElementLookup[ key ] = $( value.not( event.target ).get() );
    548 			}
    549 		} );
    550 	},
    551 
    552 	_removeClass: function( element, keys, extra ) {
    553 		return this._toggleClass( element, keys, extra, false );
    554 	},
    555 
    556 	_addClass: function( element, keys, extra ) {
    557 		return this._toggleClass( element, keys, extra, true );
    558 	},
    559 
    560 	_toggleClass: function( element, keys, extra, add ) {
    561 		add = ( typeof add === "boolean" ) ? add : extra;
    562 		var shift = ( typeof element === "string" || element === null ),
    563 			options = {
    564 				extra: shift ? keys : extra,
    565 				keys: shift ? element : keys,
    566 				element: shift ? this.element : element,
    567 				add: add
    568 			};
    569 		options.element.toggleClass( this._classes( options ), add );
    570 		return this;
    571 	},
    572 
    573 	_on: function( suppressDisabledCheck, element, handlers ) {
    574 		var delegateElement;
    575 		var instance = this;
    576 
    577 		// No suppressDisabledCheck flag, shuffle arguments
    578 		if ( typeof suppressDisabledCheck !== "boolean" ) {
    579 			handlers = element;
    580 			element = suppressDisabledCheck;
    581 			suppressDisabledCheck = false;
    582 		}
    583 
    584 		// No element argument, shuffle and use this.element
    585 		if ( !handlers ) {
    586 			handlers = element;
    587 			element = this.element;
    588 			delegateElement = this.widget();
    589 		} else {
    590 			element = delegateElement = $( element );
    591 			this.bindings = this.bindings.add( element );
    592 		}
    593 
    594 		$.each( handlers, function( event, handler ) {
    595 			function handlerProxy() {
    596 
    597 				// Allow widgets to customize the disabled handling
    598 				// - disabled as an array instead of boolean
    599 				// - disabled class as method for disabling individual parts
    600 				if ( !suppressDisabledCheck &&
    601 						( instance.options.disabled === true ||
    602 						$( this ).hasClass( "ui-state-disabled" ) ) ) {
    603 					return;
    604 				}
    605 				return ( typeof handler === "string" ? instance[ handler ] : handler )
    606 					.apply( instance, arguments );
    607 			}
    608 
    609 			// Copy the guid so direct unbinding works
    610 			if ( typeof handler !== "string" ) {
    611 				handlerProxy.guid = handler.guid =
    612 					handler.guid || handlerProxy.guid || $.guid++;
    613 			}
    614 
    615 			var match = event.match( /^([\w:-]*)\s*(.*)$/ );
    616 			var eventName = match[ 1 ] + instance.eventNamespace;
    617 			var selector = match[ 2 ];
    618 
    619 			if ( selector ) {
    620 				delegateElement.on( eventName, selector, handlerProxy );
    621 			} else {
    622 				element.on( eventName, handlerProxy );
    623 			}
    624 		} );
    625 	},
    626 
    627 	_off: function( element, eventName ) {
    628 		eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) +
    629 			this.eventNamespace;
    630 		element.off( eventName ).off( eventName );
    631 
    632 		// Clear the stack to avoid memory leaks (#10056)
    633 		this.bindings = $( this.bindings.not( element ).get() );
    634 		this.focusable = $( this.focusable.not( element ).get() );
    635 		this.hoverable = $( this.hoverable.not( element ).get() );
    636 	},
    637 
    638 	_delay: function( handler, delay ) {
    639 		function handlerProxy() {
    640 			return ( typeof handler === "string" ? instance[ handler ] : handler )
    641 				.apply( instance, arguments );
    642 		}
    643 		var instance = this;
    644 		return setTimeout( handlerProxy, delay || 0 );
    645 	},
    646 
    647 	_hoverable: function( element ) {
    648 		this.hoverable = this.hoverable.add( element );
    649 		this._on( element, {
    650 			mouseenter: function( event ) {
    651 				this._addClass( $( event.currentTarget ), null, "ui-state-hover" );
    652 			},
    653 			mouseleave: function( event ) {
    654 				this._removeClass( $( event.currentTarget ), null, "ui-state-hover" );
    655 			}
    656 		} );
    657 	},
    658 
    659 	_focusable: function( element ) {
    660 		this.focusable = this.focusable.add( element );
    661 		this._on( element, {
    662 			focusin: function( event ) {
    663 				this._addClass( $( event.currentTarget ), null, "ui-state-focus" );
    664 			},
    665 			focusout: function( event ) {
    666 				this._removeClass( $( event.currentTarget ), null, "ui-state-focus" );
    667 			}
    668 		} );
    669 	},
    670 
    671 	_trigger: function( type, event, data ) {
    672 		var prop, orig;
    673 		var callback = this.options[ type ];
    674 
    675 		data = data || {};
    676 		event = $.Event( event );
    677 		event.type = ( type === this.widgetEventPrefix ?
    678 			type :
    679 			this.widgetEventPrefix + type ).toLowerCase();
    680 
    681 		// The original event may come from any element
    682 		// so we need to reset the target on the new event
    683 		event.target = this.element[ 0 ];
    684 
    685 		// Copy original event properties over to the new event
    686 		orig = event.originalEvent;
    687 		if ( orig ) {
    688 			for ( prop in orig ) {
    689 				if ( !( prop in event ) ) {
    690 					event[ prop ] = orig[ prop ];
    691 				}
    692 			}
    693 		}
    694 
    695 		this.element.trigger( event, data );
    696 		return !( $.isFunction( callback ) &&
    697 			callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false ||
    698 			event.isDefaultPrevented() );
    699 	}
    700 };
    701 
    702 $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
    703 	$.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
    704 		if ( typeof options === "string" ) {
    705 			options = { effect: options };
    706 		}
    707 
    708 		var hasOptions;
    709 		var effectName = !options ?
    710 			method :
    711 			options === true || typeof options === "number" ?
    712 				defaultEffect :
    713 				options.effect || defaultEffect;
    714 
    715 		options = options || {};
    716 		if ( typeof options === "number" ) {
    717 			options = { duration: options };
    718 		}
    719 
    720 		hasOptions = !$.isEmptyObject( options );
    721 		options.complete = callback;
    722 
    723 		if ( options.delay ) {
    724 			element.delay( options.delay );
    725 		}
    726 
    727 		if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
    728 			element[ method ]( options );
    729 		} else if ( effectName !== method && element[ effectName ] ) {
    730 			element[ effectName ]( options.duration, options.easing, callback );
    731 		} else {
    732 			element.queue( function( next ) {
    733 				$( this )[ method ]();
    734 				if ( callback ) {
    735 					callback.call( element[ 0 ] );
    736 				}
    737 				next();
    738 			} );
    739 		}
    740 	};
    741 } );
    742 
    743 var widget = $.widget;
    744 
    745 
    746 /*!
    747  * jQuery UI :data 1.12.1
    748  * http://jqueryui.com
    749  *
    750  * Copyright jQuery Foundation and other contributors
    751  * Released under the MIT license.
    752  * http://jquery.org/license
    753  */
    754 
    755 //>>label: :data Selector
    756 //>>group: Core
    757 //>>description: Selects elements which have data stored under the specified key.
    758 //>>docs: http://api.jqueryui.com/data-selector/
    759 
    760 
    761 var data = $.extend( $.expr[ ":" ], {
    762 	data: $.expr.createPseudo ?
    763 		$.expr.createPseudo( function( dataName ) {
    764 			return function( elem ) {
    765 				return !!$.data( elem, dataName );
    766 			};
    767 		} ) :
    768 
    769 		// Support: jQuery <1.8
    770 		function( elem, i, match ) {
    771 			return !!$.data( elem, match[ 3 ] );
    772 		}
    773 } );
    774 
    775 /*!
    776  * jQuery UI Scroll Parent 1.12.1
    777  * http://jqueryui.com
    778  *
    779  * Copyright jQuery Foundation and other contributors
    780  * Released under the MIT license.
    781  * http://jquery.org/license
    782  */
    783 
    784 //>>label: scrollParent
    785 //>>group: Core
    786 //>>description: Get the closest ancestor element that is scrollable.
    787 //>>docs: http://api.jqueryui.com/scrollParent/
    788 
    789 
    790 
    791 var scrollParent = $.fn.scrollParent = function( includeHidden ) {
    792 	var position = this.css( "position" ),
    793 		excludeStaticParent = position === "absolute",
    794 		overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/,
    795 		scrollParent = this.parents().filter( function() {
    796 			var parent = $( this );
    797 			if ( excludeStaticParent && parent.css( "position" ) === "static" ) {
    798 				return false;
    799 			}
    800 			return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) +
    801 				parent.css( "overflow-x" ) );
    802 		} ).eq( 0 );
    803 
    804 	return position === "fixed" || !scrollParent.length ?
    805 		$( this[ 0 ].ownerDocument || document ) :
    806 		scrollParent;
    807 };
    808 
    809 
    810 
    811 
    812 // This file is deprecated
    813 var ie = $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
    814 
    815 /*!
    816  * jQuery UI Mouse 1.12.1
    817  * http://jqueryui.com
    818  *
    819  * Copyright jQuery Foundation and other contributors
    820  * Released under the MIT license.
    821  * http://jquery.org/license
    822  */
    823 
    824 //>>label: Mouse
    825 //>>group: Widgets
    826 //>>description: Abstracts mouse-based interactions to assist in creating certain widgets.
    827 //>>docs: http://api.jqueryui.com/mouse/
    828 
    829 
    830 
    831 var mouseHandled = false;
    832 $( document ).on( "mouseup", function() {
    833 	mouseHandled = false;
    834 } );
    835 
    836 var widgetsMouse = $.widget( "ui.mouse", {
    837 	version: "1.12.1",
    838 	options: {
    839 		cancel: "input, textarea, button, select, option",
    840 		distance: 1,
    841 		delay: 0
    842 	},
    843 	_mouseInit: function() {
    844 		var that = this;
    845 
    846 		this.element
    847 			.on( "mousedown." + this.widgetName, function( event ) {
    848 				return that._mouseDown( event );
    849 			} )
    850 			.on( "click." + this.widgetName, function( event ) {
    851 				if ( true === $.data( event.target, that.widgetName + ".preventClickEvent" ) ) {
    852 					$.removeData( event.target, that.widgetName + ".preventClickEvent" );
    853 					event.stopImmediatePropagation();
    854 					return false;
    855 				}
    856 			} );
    857 
    858 		this.started = false;
    859 	},
    860 
    861 	// TODO: make sure destroying one instance of mouse doesn't mess with
    862 	// other instances of mouse
    863 	_mouseDestroy: function() {
    864 		this.element.off( "." + this.widgetName );
    865 		if ( this._mouseMoveDelegate ) {
    866 			this.document
    867 				.off( "mousemove." + this.widgetName, this._mouseMoveDelegate )
    868 				.off( "mouseup." + this.widgetName, this._mouseUpDelegate );
    869 		}
    870 	},
    871 
    872 	_mouseDown: function( event ) {
    873 
    874 		// don't let more than one widget handle mouseStart
    875 		if ( mouseHandled ) {
    876 			return;
    877 		}
    878 
    879 		this._mouseMoved = false;
    880 
    881 		// We may have missed mouseup (out of window)
    882 		( this._mouseStarted && this._mouseUp( event ) );
    883 
    884 		this._mouseDownEvent = event;
    885 
    886 		var that = this,
    887 			btnIsLeft = ( event.which === 1 ),
    888 
    889 			// event.target.nodeName works around a bug in IE 8 with
    890 			// disabled inputs (#7620)
    891 			elIsCancel = ( typeof this.options.cancel === "string" && event.target.nodeName ?
    892 				$( event.target ).closest( this.options.cancel ).length : false );
    893 		if ( !btnIsLeft || elIsCancel || !this._mouseCapture( event ) ) {
    894 			return true;
    895 		}
    896 
    897 		this.mouseDelayMet = !this.options.delay;
    898 		if ( !this.mouseDelayMet ) {
    899 			this._mouseDelayTimer = setTimeout( function() {
    900 				that.mouseDelayMet = true;
    901 			}, this.options.delay );
    902 		}
    903 
    904 		if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) {
    905 			this._mouseStarted = ( this._mouseStart( event ) !== false );
    906 			if ( !this._mouseStarted ) {
    907 				event.preventDefault();
    908 				return true;
    909 			}
    910 		}
    911 
    912 		// Click event may never have fired (Gecko & Opera)
    913 		if ( true === $.data( event.target, this.widgetName + ".preventClickEvent" ) ) {
    914 			$.removeData( event.target, this.widgetName + ".preventClickEvent" );
    915 		}
    916 
    917 		// These delegates are required to keep context
    918 		this._mouseMoveDelegate = function( event ) {
    919 			return that._mouseMove( event );
    920 		};
    921 		this._mouseUpDelegate = function( event ) {
    922 			return that._mouseUp( event );
    923 		};
    924 
    925 		this.document
    926 			.on( "mousemove." + this.widgetName, this._mouseMoveDelegate )
    927 			.on( "mouseup." + this.widgetName, this._mouseUpDelegate );
    928 
    929 		event.preventDefault();
    930 
    931 		mouseHandled = true;
    932 		return true;
    933 	},
    934 
    935 	_mouseMove: function( event ) {
    936 
    937 		// Only check for mouseups outside the document if you've moved inside the document
    938 		// at least once. This prevents the firing of mouseup in the case of IE<9, which will
    939 		// fire a mousemove event if content is placed under the cursor. See #7778
    940 		// Support: IE <9
    941 		if ( this._mouseMoved ) {
    942 
    943 			// IE mouseup check - mouseup happened when mouse was out of window
    944 			if ( $.ui.ie && ( !document.documentMode || document.documentMode < 9 ) &&
    945 					!event.button ) {
    946 				return this._mouseUp( event );
    947 
    948 			// Iframe mouseup check - mouseup occurred in another document
    949 			} else if ( !event.which ) {
    950 
    951 				// Support: Safari <=8 - 9
    952 				// Safari sets which to 0 if you press any of the following keys
    953 				// during a drag (#14461)
    954 				if ( event.originalEvent.altKey || event.originalEvent.ctrlKey ||
    955 						event.originalEvent.metaKey || event.originalEvent.shiftKey ) {
    956 					this.ignoreMissingWhich = true;
    957 				} else if ( !this.ignoreMissingWhich ) {
    958 					return this._mouseUp( event );
    959 				}
    960 			}
    961 		}
    962 
    963 		if ( event.which || event.button ) {
    964 			this._mouseMoved = true;
    965 		}
    966 
    967 		if ( this._mouseStarted ) {
    968 			this._mouseDrag( event );
    969 			return event.preventDefault();
    970 		}
    971 
    972 		if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) {
    973 			this._mouseStarted =
    974 				( this._mouseStart( this._mouseDownEvent, event ) !== false );
    975 			( this._mouseStarted ? this._mouseDrag( event ) : this._mouseUp( event ) );
    976 		}
    977 
    978 		return !this._mouseStarted;
    979 	},
    980 
    981 	_mouseUp: function( event ) {
    982 		this.document
    983 			.off( "mousemove." + this.widgetName, this._mouseMoveDelegate )
    984 			.off( "mouseup." + this.widgetName, this._mouseUpDelegate );
    985 
    986 		if ( this._mouseStarted ) {
    987 			this._mouseStarted = false;
    988 
    989 			if ( event.target === this._mouseDownEvent.target ) {
    990 				$.data( event.target, this.widgetName + ".preventClickEvent", true );
    991 			}
    992 
    993 			this._mouseStop( event );
    994 		}
    995 
    996 		if ( this._mouseDelayTimer ) {
    997 			clearTimeout( this._mouseDelayTimer );
    998 			delete this._mouseDelayTimer;
    999 		}
   1000 
   1001 		this.ignoreMissingWhich = false;
   1002 		mouseHandled = false;
   1003 		event.preventDefault();
   1004 	},
   1005 
   1006 	_mouseDistanceMet: function( event ) {
   1007 		return ( Math.max(
   1008 				Math.abs( this._mouseDownEvent.pageX - event.pageX ),
   1009 				Math.abs( this._mouseDownEvent.pageY - event.pageY )
   1010 			) >= this.options.distance
   1011 		);
   1012 	},
   1013 
   1014 	_mouseDelayMet: function( /* event */ ) {
   1015 		return this.mouseDelayMet;
   1016 	},
   1017 
   1018 	// These are placeholder methods, to be overriden by extending plugin
   1019 	_mouseStart: function( /* event */ ) {},
   1020 	_mouseDrag: function( /* event */ ) {},
   1021 	_mouseStop: function( /* event */ ) {},
   1022 	_mouseCapture: function( /* event */ ) { return true; }
   1023 } );
   1024 
   1025 
   1026 
   1027 
   1028 // $.ui.plugin is deprecated. Use $.widget() extensions instead.
   1029 var plugin = $.ui.plugin = {
   1030 	add: function( module, option, set ) {
   1031 		var i,
   1032 			proto = $.ui[ module ].prototype;
   1033 		for ( i in set ) {
   1034 			proto.plugins[ i ] = proto.plugins[ i ] || [];
   1035 			proto.plugins[ i ].push( [ option, set[ i ] ] );
   1036 		}
   1037 	},
   1038 	call: function( instance, name, args, allowDisconnected ) {
   1039 		var i,
   1040 			set = instance.plugins[ name ];
   1041 
   1042 		if ( !set ) {
   1043 			return;
   1044 		}
   1045 
   1046 		if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode ||
   1047 				instance.element[ 0 ].parentNode.nodeType === 11 ) ) {
   1048 			return;
   1049 		}
   1050 
   1051 		for ( i = 0; i < set.length; i++ ) {
   1052 			if ( instance.options[ set[ i ][ 0 ] ] ) {
   1053 				set[ i ][ 1 ].apply( instance.element, args );
   1054 			}
   1055 		}
   1056 	}
   1057 };
   1058 
   1059 
   1060 
   1061 var safeActiveElement = $.ui.safeActiveElement = function( document ) {
   1062 	var activeElement;
   1063 
   1064 	// Support: IE 9 only
   1065 	// IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
   1066 	try {
   1067 		activeElement = document.activeElement;
   1068 	} catch ( error ) {
   1069 		activeElement = document.body;
   1070 	}
   1071 
   1072 	// Support: IE 9 - 11 only
   1073 	// IE may return null instead of an element
   1074 	// Interestingly, this only seems to occur when NOT in an iframe
   1075 	if ( !activeElement ) {
   1076 		activeElement = document.body;
   1077 	}
   1078 
   1079 	// Support: IE 11 only
   1080 	// IE11 returns a seemingly empty object in some cases when accessing
   1081 	// document.activeElement from an <iframe>
   1082 	if ( !activeElement.nodeName ) {
   1083 		activeElement = document.body;
   1084 	}
   1085 
   1086 	return activeElement;
   1087 };
   1088 
   1089 
   1090 
   1091 var safeBlur = $.ui.safeBlur = function( element ) {
   1092 
   1093 	// Support: IE9 - 10 only
   1094 	// If the <body> is blurred, IE will switch windows, see #9420
   1095 	if ( element && element.nodeName.toLowerCase() !== "body" ) {
   1096 		$( element ).trigger( "blur" );
   1097 	}
   1098 };
   1099 
   1100 
   1101 /*!
   1102  * jQuery UI Draggable 1.12.1
   1103  * http://jqueryui.com
   1104  *
   1105  * Copyright jQuery Foundation and other contributors
   1106  * Released under the MIT license.
   1107  * http://jquery.org/license
   1108  */
   1109 
   1110 //>>label: Draggable
   1111 //>>group: Interactions
   1112 //>>description: Enables dragging functionality for any element.
   1113 //>>docs: http://api.jqueryui.com/draggable/
   1114 //>>demos: http://jqueryui.com/draggable/
   1115 //>>css.structure: ../../themes/base/draggable.css
   1116 
   1117 
   1118 
   1119 $.widget( "ui.draggable", $.ui.mouse, {
   1120 	version: "1.12.1",
   1121 	widgetEventPrefix: "drag",
   1122 	options: {
   1123 		addClasses: true,
   1124 		appendTo: "parent",
   1125 		axis: false,
   1126 		connectToSortable: false,
   1127 		containment: false,
   1128 		cursor: "auto",
   1129 		cursorAt: false,
   1130 		grid: false,
   1131 		handle: false,
   1132 		helper: "original",
   1133 		iframeFix: false,
   1134 		opacity: false,
   1135 		refreshPositions: false,
   1136 		revert: false,
   1137 		revertDuration: 500,
   1138 		scope: "default",
   1139 		scroll: true,
   1140 		scrollSensitivity: 20,
   1141 		scrollSpeed: 20,
   1142 		snap: false,
   1143 		snapMode: "both",
   1144 		snapTolerance: 20,
   1145 		stack: false,
   1146 		zIndex: false,
   1147 
   1148 		// Callbacks
   1149 		drag: null,
   1150 		start: null,
   1151 		stop: null
   1152 	},
   1153 	_create: function() {
   1154 
   1155 		if ( this.options.helper === "original" ) {
   1156 			this._setPositionRelative();
   1157 		}
   1158 		if ( this.options.addClasses ) {
   1159 			this._addClass( "ui-draggable" );
   1160 		}
   1161 		this._setHandleClassName();
   1162 
   1163 		this._mouseInit();
   1164 	},
   1165 
   1166 	_setOption: function( key, value ) {
   1167 		this._super( key, value );
   1168 		if ( key === "handle" ) {
   1169 			this._removeHandleClassName();
   1170 			this._setHandleClassName();
   1171 		}
   1172 	},
   1173 
   1174 	_destroy: function() {
   1175 		if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) {
   1176 			this.destroyOnClear = true;
   1177 			return;
   1178 		}
   1179 		this._removeHandleClassName();
   1180 		this._mouseDestroy();
   1181 	},
   1182 
   1183 	_mouseCapture: function( event ) {
   1184 		var o = this.options;
   1185 
   1186 		// Among others, prevent a drag on a resizable-handle
   1187 		if ( this.helper || o.disabled ||
   1188 				$( event.target ).closest( ".ui-resizable-handle" ).length > 0 ) {
   1189 			return false;
   1190 		}
   1191 
   1192 		//Quit if we're not on a valid handle
   1193 		this.handle = this._getHandle( event );
   1194 		if ( !this.handle ) {
   1195 			return false;
   1196 		}
   1197 
   1198 		this._blurActiveElement( event );
   1199 
   1200 		this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix );
   1201 
   1202 		return true;
   1203 
   1204 	},
   1205 
   1206 	_blockFrames: function( selector ) {
   1207 		this.iframeBlocks = this.document.find( selector ).map( function() {
   1208 			var iframe = $( this );
   1209 
   1210 			return $( "<div>" )
   1211 				.css( "position", "absolute" )
   1212 				.appendTo( iframe.parent() )
   1213 				.outerWidth( iframe.outerWidth() )
   1214 				.outerHeight( iframe.outerHeight() )
   1215 				.offset( iframe.offset() )[ 0 ];
   1216 		} );
   1217 	},
   1218 
   1219 	_unblockFrames: function() {
   1220 		if ( this.iframeBlocks ) {
   1221 			this.iframeBlocks.remove();
   1222 			delete this.iframeBlocks;
   1223 		}
   1224 	},
   1225 
   1226 	_blurActiveElement: function( event ) {
   1227 		var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ),
   1228 			target = $( event.target );
   1229 
   1230 		// Don't blur if the event occurred on an element that is within
   1231 		// the currently focused element
   1232 		// See #10527, #12472
   1233 		if ( target.closest( activeElement ).length ) {
   1234 			return;
   1235 		}
   1236 
   1237 		// Blur any element that currently has focus, see #4261
   1238 		$.ui.safeBlur( activeElement );
   1239 	},
   1240 
   1241 	_mouseStart: function( event ) {
   1242 
   1243 		var o = this.options;
   1244 
   1245 		//Create and append the visible helper
   1246 		this.helper = this._createHelper( event );
   1247 
   1248 		this._addClass( this.helper, "ui-draggable-dragging" );
   1249 
   1250 		//Cache the helper size
   1251 		this._cacheHelperProportions();
   1252 
   1253 		//If ddmanager is used for droppables, set the global draggable
   1254 		if ( $.ui.ddmanager ) {
   1255 			$.ui.ddmanager.current = this;
   1256 		}
   1257 
   1258 		/*
   1259 		 * - Position generation -
   1260 		 * This block generates everything position related - it's the core of draggables.
   1261 		 */
   1262 
   1263 		//Cache the margins of the original element
   1264 		this._cacheMargins();
   1265 
   1266 		//Store the helper's css position
   1267 		this.cssPosition = this.helper.css( "position" );
   1268 		this.scrollParent = this.helper.scrollParent( true );
   1269 		this.offsetParent = this.helper.offsetParent();
   1270 		this.hasFixedAncestor = this.helper.parents().filter( function() {
   1271 				return $( this ).css( "position" ) === "fixed";
   1272 			} ).length > 0;
   1273 
   1274 		//The element's absolute position on the page minus margins
   1275 		this.positionAbs = this.element.offset();
   1276 		this._refreshOffsets( event );
   1277 
   1278 		//Generate the original position
   1279 		this.originalPosition = this.position = this._generatePosition( event, false );
   1280 		this.originalPageX = event.pageX;
   1281 		this.originalPageY = event.pageY;
   1282 
   1283 		//Adjust the mouse offset relative to the helper if "cursorAt" is supplied
   1284 		( o.cursorAt && this._adjustOffsetFromHelper( o.cursorAt ) );
   1285 
   1286 		//Set a containment if given in the options
   1287 		this._setContainment();
   1288 
   1289 		//Trigger event + callbacks
   1290 		if ( this._trigger( "start", event ) === false ) {
   1291 			this._clear();
   1292 			return false;
   1293 		}
   1294 
   1295 		//Recache the helper size
   1296 		this._cacheHelperProportions();
   1297 
   1298 		//Prepare the droppable offsets
   1299 		if ( $.ui.ddmanager && !o.dropBehaviour ) {
   1300 			$.ui.ddmanager.prepareOffsets( this, event );
   1301 		}
   1302 
   1303 		// Execute the drag once - this causes the helper not to be visible before getting its
   1304 		// correct position
   1305 		this._mouseDrag( event, true );
   1306 
   1307 		// If the ddmanager is used for droppables, inform the manager that dragging has started
   1308 		// (see #5003)
   1309 		if ( $.ui.ddmanager ) {
   1310 			$.ui.ddmanager.dragStart( this, event );
   1311 		}
   1312 
   1313 		return true;
   1314 	},
   1315 
   1316 	_refreshOffsets: function( event ) {
   1317 		this.offset = {
   1318 			top: this.positionAbs.top - this.margins.top,
   1319 			left: this.positionAbs.left - this.margins.left,
   1320 			scroll: false,
   1321 			parent: this._getParentOffset(),
   1322 			relative: this._getRelativeOffset()
   1323 		};
   1324 
   1325 		this.offset.click = {
   1326 			left: event.pageX - this.offset.left,
   1327 			top: event.pageY - this.offset.top
   1328 		};
   1329 	},
   1330 
   1331 	_mouseDrag: function( event, noPropagation ) {
   1332 
   1333 		// reset any necessary cached properties (see #5009)
   1334 		if ( this.hasFixedAncestor ) {
   1335 			this.offset.parent = this._getParentOffset();
   1336 		}
   1337 
   1338 		//Compute the helpers position
   1339 		this.position = this._generatePosition( event, true );
   1340 		this.positionAbs = this._convertPositionTo( "absolute" );
   1341 
   1342 		//Call plugins and callbacks and use the resulting position if something is returned
   1343 		if ( !noPropagation ) {
   1344 			var ui = this._uiHash();
   1345 			if ( this._trigger( "drag", event, ui ) === false ) {
   1346 				this._mouseUp( new $.Event( "mouseup", event ) );
   1347 				return false;
   1348 			}
   1349 			this.position = ui.position;
   1350 		}
   1351 
   1352 		this.helper[ 0 ].style.left = this.position.left + "px";
   1353 		this.helper[ 0 ].style.top = this.position.top + "px";
   1354 
   1355 		if ( $.ui.ddmanager ) {
   1356 			$.ui.ddmanager.drag( this, event );
   1357 		}
   1358 
   1359 		return false;
   1360 	},
   1361 
   1362 	_mouseStop: function( event ) {
   1363 
   1364 		//If we are using droppables, inform the manager about the drop
   1365 		var that = this,
   1366 			dropped = false;
   1367 		if ( $.ui.ddmanager && !this.options.dropBehaviour ) {
   1368 			dropped = $.ui.ddmanager.drop( this, event );
   1369 		}
   1370 
   1371 		//if a drop comes from outside (a sortable)
   1372 		if ( this.dropped ) {
   1373 			dropped = this.dropped;
   1374 			this.dropped = false;
   1375 		}
   1376 
   1377 		if ( ( this.options.revert === "invalid" && !dropped ) ||
   1378 				( this.options.revert === "valid" && dropped ) ||
   1379 				this.options.revert === true || ( $.isFunction( this.options.revert ) &&
   1380 				this.options.revert.call( this.element, dropped ) )
   1381 		) {
   1382 			$( this.helper ).animate(
   1383 				this.originalPosition,
   1384 				parseInt( this.options.revertDuration, 10 ),
   1385 				function() {
   1386 					if ( that._trigger( "stop", event ) !== false ) {
   1387 						that._clear();
   1388 					}
   1389 				}
   1390 			);
   1391 		} else {
   1392 			if ( this._trigger( "stop", event ) !== false ) {
   1393 				this._clear();
   1394 			}
   1395 		}
   1396 
   1397 		return false;
   1398 	},
   1399 
   1400 	_mouseUp: function( event ) {
   1401 		this._unblockFrames();
   1402 
   1403 		// If the ddmanager is used for droppables, inform the manager that dragging has stopped
   1404 		// (see #5003)
   1405 		if ( $.ui.ddmanager ) {
   1406 			$.ui.ddmanager.dragStop( this, event );
   1407 		}
   1408 
   1409 		// Only need to focus if the event occurred on the draggable itself, see #10527
   1410 		if ( this.handleElement.is( event.target ) ) {
   1411 
   1412 			// The interaction is over; whether or not the click resulted in a drag,
   1413 			// focus the element
   1414 			this.element.trigger( "focus" );
   1415 		}
   1416 
   1417 		return $.ui.mouse.prototype._mouseUp.call( this, event );
   1418 	},
   1419 
   1420 	cancel: function() {
   1421 
   1422 		if ( this.helper.is( ".ui-draggable-dragging" ) ) {
   1423 			this._mouseUp( new $.Event( "mouseup", { target: this.element[ 0 ] } ) );
   1424 		} else {
   1425 			this._clear();
   1426 		}
   1427 
   1428 		return this;
   1429 
   1430 	},
   1431 
   1432 	_getHandle: function( event ) {
   1433 		return this.options.handle ?
   1434 			!!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
   1435 			true;
   1436 	},
   1437 
   1438 	_setHandleClassName: function() {
   1439 		this.handleElement = this.options.handle ?
   1440 			this.element.find( this.options.handle ) : this.element;
   1441 		this._addClass( this.handleElement, "ui-draggable-handle" );
   1442 	},
   1443 
   1444 	_removeHandleClassName: function() {
   1445 		this._removeClass( this.handleElement, "ui-draggable-handle" );
   1446 	},
   1447 
   1448 	_createHelper: function( event ) {
   1449 
   1450 		var o = this.options,
   1451 			helperIsFunction = $.isFunction( o.helper ),
   1452 			helper = helperIsFunction ?
   1453 				$( o.helper.apply( this.element[ 0 ], [ event ] ) ) :
   1454 				( o.helper === "clone" ?
   1455 					this.element.clone().removeAttr( "id" ) :
   1456 					this.element );
   1457 
   1458 		if ( !helper.parents( "body" ).length ) {
   1459 			helper.appendTo( ( o.appendTo === "parent" ?
   1460 				this.element[ 0 ].parentNode :
   1461 				o.appendTo ) );
   1462 		}
   1463 
   1464 		// Http://bugs.jqueryui.com/ticket/9446
   1465 		// a helper function can return the original element
   1466 		// which wouldn't have been set to relative in _create
   1467 		if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) {
   1468 			this._setPositionRelative();
   1469 		}
   1470 
   1471 		if ( helper[ 0 ] !== this.element[ 0 ] &&
   1472 				!( /(fixed|absolute)/ ).test( helper.css( "position" ) ) ) {
   1473 			helper.css( "position", "absolute" );
   1474 		}
   1475 
   1476 		return helper;
   1477 
   1478 	},
   1479 
   1480 	_setPositionRelative: function() {
   1481 		if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) {
   1482 			this.element[ 0 ].style.position = "relative";
   1483 		}
   1484 	},
   1485 
   1486 	_adjustOffsetFromHelper: function( obj ) {
   1487 		if ( typeof obj === "string" ) {
   1488 			obj = obj.split( " " );
   1489 		}
   1490 		if ( $.isArray( obj ) ) {
   1491 			obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 };
   1492 		}
   1493 		if ( "left" in obj ) {
   1494 			this.offset.click.left = obj.left + this.margins.left;
   1495 		}
   1496 		if ( "right" in obj ) {
   1497 			this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
   1498 		}
   1499 		if ( "top" in obj ) {
   1500 			this.offset.click.top = obj.top + this.margins.top;
   1501 		}
   1502 		if ( "bottom" in obj ) {
   1503 			this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
   1504 		}
   1505 	},
   1506 
   1507 	_isRootNode: function( element ) {
   1508 		return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ];
   1509 	},
   1510 
   1511 	_getParentOffset: function() {
   1512 
   1513 		//Get the offsetParent and cache its position
   1514 		var po = this.offsetParent.offset(),
   1515 			document = this.document[ 0 ];
   1516 
   1517 		// This is a special case where we need to modify a offset calculated on start, since the
   1518 		// following happened:
   1519 		// 1. The position of the helper is absolute, so it's position is calculated based on the
   1520 		// next positioned parent
   1521 		// 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't
   1522 		// the document, which means that the scroll is included in the initial calculation of the
   1523 		// offset of the parent, and never recalculated upon drag
   1524 		if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== document &&
   1525 				$.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) {
   1526 			po.left += this.scrollParent.scrollLeft();
   1527 			po.top += this.scrollParent.scrollTop();
   1528 		}
   1529 
   1530 		if ( this._isRootNode( this.offsetParent[ 0 ] ) ) {
   1531 			po = { top: 0, left: 0 };
   1532 		}
   1533 
   1534 		return {
   1535 			top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ),
   1536 			left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 )
   1537 		};
   1538 
   1539 	},
   1540 
   1541 	_getRelativeOffset: function() {
   1542 		if ( this.cssPosition !== "relative" ) {
   1543 			return { top: 0, left: 0 };
   1544 		}
   1545 
   1546 		var p = this.element.position(),
   1547 			scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
   1548 
   1549 		return {
   1550 			top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) +
   1551 				( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ),
   1552 			left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) +
   1553 				( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 )
   1554 		};
   1555 
   1556 	},
   1557 
   1558 	_cacheMargins: function() {
   1559 		this.margins = {
   1560 			left: ( parseInt( this.element.css( "marginLeft" ), 10 ) || 0 ),
   1561 			top: ( parseInt( this.element.css( "marginTop" ), 10 ) || 0 ),
   1562 			right: ( parseInt( this.element.css( "marginRight" ), 10 ) || 0 ),
   1563 			bottom: ( parseInt( this.element.css( "marginBottom" ), 10 ) || 0 )
   1564 		};
   1565 	},
   1566 
   1567 	_cacheHelperProportions: function() {
   1568 		this.helperProportions = {
   1569 			width: this.helper.outerWidth(),
   1570 			height: this.helper.outerHeight()
   1571 		};
   1572 	},
   1573 
   1574 	_setContainment: function() {
   1575 
   1576 		var isUserScrollable, c, ce,
   1577 			o = this.options,
   1578 			document = this.document[ 0 ];
   1579 
   1580 		this.relativeContainer = null;
   1581 
   1582 		if ( !o.containment ) {
   1583 			this.containment = null;
   1584 			return;
   1585 		}
   1586 
   1587 		if ( o.containment === "window" ) {
   1588 			this.containment = [
   1589 				$( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
   1590 				$( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
   1591 				$( window ).scrollLeft() + $( window ).width() -
   1592 					this.helperProportions.width - this.margins.left,
   1593 				$( window ).scrollTop() +
   1594 					( $( window ).height() || document.body.parentNode.scrollHeight ) -
   1595 					this.helperProportions.height - this.margins.top
   1596 			];
   1597 			return;
   1598 		}
   1599 
   1600 		if ( o.containment === "document" ) {
   1601 			this.containment = [
   1602 				0,
   1603 				0,
   1604 				$( document ).width() - this.helperProportions.width - this.margins.left,
   1605 				( $( document ).height() || document.body.parentNode.scrollHeight ) -
   1606 					this.helperProportions.height - this.margins.top
   1607 			];
   1608 			return;
   1609 		}
   1610 
   1611 		if ( o.containment.constructor === Array ) {
   1612 			this.containment = o.containment;
   1613 			return;
   1614 		}
   1615 
   1616 		if ( o.containment === "parent" ) {
   1617 			o.containment = this.helper[ 0 ].parentNode;
   1618 		}
   1619 
   1620 		c = $( o.containment );
   1621 		ce = c[ 0 ];
   1622 
   1623 		if ( !ce ) {
   1624 			return;
   1625 		}
   1626 
   1627 		isUserScrollable = /(scroll|auto)/.test( c.css( "overflow" ) );
   1628 
   1629 		this.containment = [
   1630 			( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) +
   1631 				( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
   1632 			( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) +
   1633 				( parseInt( c.css( "paddingTop" ), 10 ) || 0 ),
   1634 			( isUserScrollable ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
   1635 				( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) -
   1636 				( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) -
   1637 				this.helperProportions.width -
   1638 				this.margins.left -
   1639 				this.margins.right,
   1640 			( isUserScrollable ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
   1641 				( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) -
   1642 				( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) -
   1643 				this.helperProportions.height -
   1644 				this.margins.top -
   1645 				this.margins.bottom
   1646 		];
   1647 		this.relativeContainer = c;
   1648 	},
   1649 
   1650 	_convertPositionTo: function( d, pos ) {
   1651 
   1652 		if ( !pos ) {
   1653 			pos = this.position;
   1654 		}
   1655 
   1656 		var mod = d === "absolute" ? 1 : -1,
   1657 			scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
   1658 
   1659 		return {
   1660 			top: (
   1661 
   1662 				// The absolute mouse position
   1663 				pos.top	+
   1664 
   1665 				// Only for relative positioned nodes: Relative offset from element to offset parent
   1666 				this.offset.relative.top * mod +
   1667 
   1668 				// The offsetParent's offset without borders (offset + border)
   1669 				this.offset.parent.top * mod -
   1670 				( ( this.cssPosition === "fixed" ?
   1671 					-this.offset.scroll.top :
   1672 					( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod )
   1673 			),
   1674 			left: (
   1675 
   1676 				// The absolute mouse position
   1677 				pos.left +
   1678 
   1679 				// Only for relative positioned nodes: Relative offset from element to offset parent
   1680 				this.offset.relative.left * mod +
   1681 
   1682 				// The offsetParent's offset without borders (offset + border)
   1683 				this.offset.parent.left * mod	-
   1684 				( ( this.cssPosition === "fixed" ?
   1685 					-this.offset.scroll.left :
   1686 					( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod )
   1687 			)
   1688 		};
   1689 
   1690 	},
   1691 
   1692 	_generatePosition: function( event, constrainPosition ) {
   1693 
   1694 		var containment, co, top, left,
   1695 			o = this.options,
   1696 			scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ),
   1697 			pageX = event.pageX,
   1698 			pageY = event.pageY;
   1699 
   1700 		// Cache the scroll
   1701 		if ( !scrollIsRootNode || !this.offset.scroll ) {
   1702 			this.offset.scroll = {
   1703 				top: this.scrollParent.scrollTop(),
   1704 				left: this.scrollParent.scrollLeft()
   1705 			};
   1706 		}
   1707 
   1708 		/*
   1709 		 * - Position constraining -
   1710 		 * Constrain the position to a mix of grid, containment.
   1711 		 */
   1712 
   1713 		// If we are not dragging yet, we won't check for options
   1714 		if ( constrainPosition ) {
   1715 			if ( this.containment ) {
   1716 				if ( this.relativeContainer ) {
   1717 					co = this.relativeContainer.offset();
   1718 					containment = [
   1719 						this.containment[ 0 ] + co.left,
   1720 						this.containment[ 1 ] + co.top,
   1721 						this.containment[ 2 ] + co.left,
   1722 						this.containment[ 3 ] + co.top
   1723 					];
   1724 				} else {
   1725 					containment = this.containment;
   1726 				}
   1727 
   1728 				if ( event.pageX - this.offset.click.left < containment[ 0 ] ) {
   1729 					pageX = containment[ 0 ] + this.offset.click.left;
   1730 				}
   1731 				if ( event.pageY - this.offset.click.top < containment[ 1 ] ) {
   1732 					pageY = containment[ 1 ] + this.offset.click.top;
   1733 				}
   1734 				if ( event.pageX - this.offset.click.left > containment[ 2 ] ) {
   1735 					pageX = containment[ 2 ] + this.offset.click.left;
   1736 				}
   1737 				if ( event.pageY - this.offset.click.top > containment[ 3 ] ) {
   1738 					pageY = containment[ 3 ] + this.offset.click.top;
   1739 				}
   1740 			}
   1741 
   1742 			if ( o.grid ) {
   1743 
   1744 				//Check for grid elements set to 0 to prevent divide by 0 error causing invalid
   1745 				// argument errors in IE (see ticket #6950)
   1746 				top = o.grid[ 1 ] ? this.originalPageY + Math.round( ( pageY -
   1747 					this.originalPageY ) / o.grid[ 1 ] ) * o.grid[ 1 ] : this.originalPageY;
   1748 				pageY = containment ? ( ( top - this.offset.click.top >= containment[ 1 ] ||
   1749 					top - this.offset.click.top > containment[ 3 ] ) ?
   1750 						top :
   1751 						( ( top - this.offset.click.top >= containment[ 1 ] ) ?
   1752 							top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) : top;
   1753 
   1754 				left = o.grid[ 0 ] ? this.originalPageX +
   1755 					Math.round( ( pageX - this.originalPageX ) / o.grid[ 0 ] ) * o.grid[ 0 ] :
   1756 					this.originalPageX;
   1757 				pageX = containment ? ( ( left - this.offset.click.left >= containment[ 0 ] ||
   1758 					left - this.offset.click.left > containment[ 2 ] ) ?
   1759 						left :
   1760 						( ( left - this.offset.click.left >= containment[ 0 ] ) ?
   1761 							left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) : left;
   1762 			}
   1763 
   1764 			if ( o.axis === "y" ) {
   1765 				pageX = this.originalPageX;
   1766 			}
   1767 
   1768 			if ( o.axis === "x" ) {
   1769 				pageY = this.originalPageY;
   1770 			}
   1771 		}
   1772 
   1773 		return {
   1774 			top: (
   1775 
   1776 				// The absolute mouse position
   1777 				pageY -
   1778 
   1779 				// Click offset (relative to the element)
   1780 				this.offset.click.top -
   1781 
   1782 				// Only for relative positioned nodes: Relative offset from element to offset parent
   1783 				this.offset.relative.top -
   1784 
   1785 				// The offsetParent's offset without borders (offset + border)
   1786 				this.offset.parent.top +
   1787 				( this.cssPosition === "fixed" ?
   1788 					-this.offset.scroll.top :
   1789 					( scrollIsRootNode ? 0 : this.offset.scroll.top ) )
   1790 			),
   1791 			left: (
   1792 
   1793 				// The absolute mouse position
   1794 				pageX -
   1795 
   1796 				// Click offset (relative to the element)
   1797 				this.offset.click.left -
   1798 
   1799 				// Only for relative positioned nodes: Relative offset from element to offset parent
   1800 				this.offset.relative.left -
   1801 
   1802 				// The offsetParent's offset without borders (offset + border)
   1803 				this.offset.parent.left +
   1804 				( this.cssPosition === "fixed" ?
   1805 					-this.offset.scroll.left :
   1806 					( scrollIsRootNode ? 0 : this.offset.scroll.left ) )
   1807 			)
   1808 		};
   1809 
   1810 	},
   1811 
   1812 	_clear: function() {
   1813 		this._removeClass( this.helper, "ui-draggable-dragging" );
   1814 		if ( this.helper[ 0 ] !== this.element[ 0 ] && !this.cancelHelperRemoval ) {
   1815 			this.helper.remove();
   1816 		}
   1817 		this.helper = null;
   1818 		this.cancelHelperRemoval = false;
   1819 		if ( this.destroyOnClear ) {
   1820 			this.destroy();
   1821 		}
   1822 	},
   1823 
   1824 	// From now on bulk stuff - mainly helpers
   1825 
   1826 	_trigger: function( type, event, ui ) {
   1827 		ui = ui || this._uiHash();
   1828 		$.ui.plugin.call( this, type, [ event, ui, this ], true );
   1829 
   1830 		// Absolute position and offset (see #6884 ) have to be recalculated after plugins
   1831 		if ( /^(drag|start|stop)/.test( type ) ) {
   1832 			this.positionAbs = this._convertPositionTo( "absolute" );
   1833 			ui.offset = this.positionAbs;
   1834 		}
   1835 		return $.Widget.prototype._trigger.call( this, type, event, ui );
   1836 	},
   1837 
   1838 	plugins: {},
   1839 
   1840 	_uiHash: function() {
   1841 		return {
   1842 			helper: this.helper,
   1843 			position: this.position,
   1844 			originalPosition: this.originalPosition,
   1845 			offset: this.positionAbs
   1846 		};
   1847 	}
   1848 
   1849 } );
   1850 
   1851 $.ui.plugin.add( "draggable", "connectToSortable", {
   1852 	start: function( event, ui, draggable ) {
   1853 		var uiSortable = $.extend( {}, ui, {
   1854 			item: draggable.element
   1855 		} );
   1856 
   1857 		draggable.sortables = [];
   1858 		$( draggable.options.connectToSortable ).each( function() {
   1859 			var sortable = $( this ).sortable( "instance" );
   1860 
   1861 			if ( sortable && !sortable.options.disabled ) {
   1862 				draggable.sortables.push( sortable );
   1863 
   1864 				// RefreshPositions is called at drag start to refresh the containerCache
   1865 				// which is used in drag. This ensures it's initialized and synchronized
   1866 				// with any changes that might have happened on the page since initialization.
   1867 				sortable.refreshPositions();
   1868 				sortable._trigger( "activate", event, uiSortable );
   1869 			}
   1870 		} );
   1871 	},
   1872 	stop: function( event, ui, draggable ) {
   1873 		var uiSortable = $.extend( {}, ui, {
   1874 			item: draggable.element
   1875 		} );
   1876 
   1877 		draggable.cancelHelperRemoval = false;
   1878 
   1879 		$.each( draggable.sortables, function() {
   1880 			var sortable = this;
   1881 
   1882 			if ( sortable.isOver ) {
   1883 				sortable.isOver = 0;
   1884 
   1885 				// Allow this sortable to handle removing the helper
   1886 				draggable.cancelHelperRemoval = true;
   1887 				sortable.cancelHelperRemoval = false;
   1888 
   1889 				// Use _storedCSS To restore properties in the sortable,
   1890 				// as this also handles revert (#9675) since the draggable
   1891 				// may have modified them in unexpected ways (#8809)
   1892 				sortable._storedCSS = {
   1893 					position: sortable.placeholder.css( "position" ),
   1894 					top: sortable.placeholder.css( "top" ),
   1895 					left: sortable.placeholder.css( "left" )
   1896 				};
   1897 
   1898 				sortable._mouseStop( event );
   1899 
   1900 				// Once drag has ended, the sortable should return to using
   1901 				// its original helper, not the shared helper from draggable
   1902 				sortable.options.helper = sortable.options._helper;
   1903 			} else {
   1904 
   1905 				// Prevent this Sortable from removing the helper.
   1906 				// However, don't set the draggable to remove the helper
   1907 				// either as another connected Sortable may yet handle the removal.
   1908 				sortable.cancelHelperRemoval = true;
   1909 
   1910 				sortable._trigger( "deactivate", event, uiSortable );
   1911 			}
   1912 		} );
   1913 	},
   1914 	drag: function( event, ui, draggable ) {
   1915 		$.each( draggable.sortables, function() {
   1916 			var innermostIntersecting = false,
   1917 				sortable = this;
   1918 
   1919 			// Copy over variables that sortable's _intersectsWith uses
   1920 			sortable.positionAbs = draggable.positionAbs;
   1921 			sortable.helperProportions = draggable.helperProportions;
   1922 			sortable.offset.click = draggable.offset.click;
   1923 
   1924 			if ( sortable._intersectsWith( sortable.containerCache ) ) {
   1925 				innermostIntersecting = true;
   1926 
   1927 				$.each( draggable.sortables, function() {
   1928 
   1929 					// Copy over variables that sortable's _intersectsWith uses
   1930 					this.positionAbs = draggable.positionAbs;
   1931 					this.helperProportions = draggable.helperProportions;
   1932 					this.offset.click = draggable.offset.click;
   1933 
   1934 					if ( this !== sortable &&
   1935 							this._intersectsWith( this.containerCache ) &&
   1936 							$.contains( sortable.element[ 0 ], this.element[ 0 ] ) ) {
   1937 						innermostIntersecting = false;
   1938 					}
   1939 
   1940 					return innermostIntersecting;
   1941 				} );
   1942 			}
   1943 
   1944 			if ( innermostIntersecting ) {
   1945 
   1946 				// If it intersects, we use a little isOver variable and set it once,
   1947 				// so that the move-in stuff gets fired only once.
   1948 				if ( !sortable.isOver ) {
   1949 					sortable.isOver = 1;
   1950 
   1951 					// Store draggable's parent in case we need to reappend to it later.
   1952 					draggable._parent = ui.helper.parent();
   1953 
   1954 					sortable.currentItem = ui.helper
   1955 						.appendTo( sortable.element )
   1956 						.data( "ui-sortable-item", true );
   1957 
   1958 					// Store helper option to later restore it
   1959 					sortable.options._helper = sortable.options.helper;
   1960 
   1961 					sortable.options.helper = function() {
   1962 						return ui.helper[ 0 ];
   1963 					};
   1964 
   1965 					// Fire the start events of the sortable with our passed browser event,
   1966 					// and our own helper (so it doesn't create a new one)
   1967 					event.target = sortable.currentItem[ 0 ];
   1968 					sortable._mouseCapture( event, true );
   1969 					sortable._mouseStart( event, true, true );
   1970 
   1971 					// Because the browser event is way off the new appended portlet,
   1972 					// modify necessary variables to reflect the changes
   1973 					sortable.offset.click.top = draggable.offset.click.top;
   1974 					sortable.offset.click.left = draggable.offset.click.left;
   1975 					sortable.offset.parent.left -= draggable.offset.parent.left -
   1976 						sortable.offset.parent.left;
   1977 					sortable.offset.parent.top -= draggable.offset.parent.top -
   1978 						sortable.offset.parent.top;
   1979 
   1980 					draggable._trigger( "toSortable", event );
   1981 
   1982 					// Inform draggable that the helper is in a valid drop zone,
   1983 					// used solely in the revert option to handle "valid/invalid".
   1984 					draggable.dropped = sortable.element;
   1985 
   1986 					// Need to refreshPositions of all sortables in the case that
   1987 					// adding to one sortable changes the location of the other sortables (#9675)
   1988 					$.each( draggable.sortables, function() {
   1989 						this.refreshPositions();
   1990 					} );
   1991 
   1992 					// Hack so receive/update callbacks work (mostly)
   1993 					draggable.currentItem = draggable.element;
   1994 					sortable.fromOutside = draggable;
   1995 				}
   1996 
   1997 				if ( sortable.currentItem ) {
   1998 					sortable._mouseDrag( event );
   1999 
   2000 					// Copy the sortable's position because the draggable's can potentially reflect
   2001 					// a relative position, while sortable is always absolute, which the dragged
   2002 					// element has now become. (#8809)
   2003 					ui.position = sortable.position;
   2004 				}
   2005 			} else {
   2006 
   2007 				// If it doesn't intersect with the sortable, and it intersected before,
   2008 				// we fake the drag stop of the sortable, but make sure it doesn't remove
   2009 				// the helper by using cancelHelperRemoval.
   2010 				if ( sortable.isOver ) {
   2011 
   2012 					sortable.isOver = 0;
   2013 					sortable.cancelHelperRemoval = true;
   2014 
   2015 					// Calling sortable's mouseStop would trigger a revert,
   2016 					// so revert must be temporarily false until after mouseStop is called.
   2017 					sortable.options._revert = sortable.options.revert;
   2018 					sortable.options.revert = false;
   2019 
   2020 					sortable._trigger( "out", event, sortable._uiHash( sortable ) );
   2021 					sortable._mouseStop( event, true );
   2022 
   2023 					// Restore sortable behaviors that were modfied
   2024 					// when the draggable entered the sortable area (#9481)
   2025 					sortable.options.revert = sortable.options._revert;
   2026 					sortable.options.helper = sortable.options._helper;
   2027 
   2028 					if ( sortable.placeholder ) {
   2029 						sortable.placeholder.remove();
   2030 					}
   2031 
   2032 					// Restore and recalculate the draggable's offset considering the sortable
   2033 					// may have modified them in unexpected ways. (#8809, #10669)
   2034 					ui.helper.appendTo( draggable._parent );
   2035 					draggable._refreshOffsets( event );
   2036 					ui.position = draggable._generatePosition( event, true );
   2037 
   2038 					draggable._trigger( "fromSortable", event );
   2039 
   2040 					// Inform draggable that the helper is no longer in a valid drop zone
   2041 					draggable.dropped = false;
   2042 
   2043 					// Need to refreshPositions of all sortables just in case removing
   2044 					// from one sortable changes the location of other sortables (#9675)
   2045 					$.each( draggable.sortables, function() {
   2046 						this.refreshPositions();
   2047 					} );
   2048 				}
   2049 			}
   2050 		} );
   2051 	}
   2052 } );
   2053 
   2054 $.ui.plugin.add( "draggable", "cursor", {
   2055 	start: function( event, ui, instance ) {
   2056 		var t = $( "body" ),
   2057 			o = instance.options;
   2058 
   2059 		if ( t.css( "cursor" ) ) {
   2060 			o._cursor = t.css( "cursor" );
   2061 		}
   2062 		t.css( "cursor", o.cursor );
   2063 	},
   2064 	stop: function( event, ui, instance ) {
   2065 		var o = instance.options;
   2066 		if ( o._cursor ) {
   2067 			$( "body" ).css( "cursor", o._cursor );
   2068 		}
   2069 	}
   2070 } );
   2071 
   2072 $.ui.plugin.add( "draggable", "opacity", {
   2073 	start: function( event, ui, instance ) {
   2074 		var t = $( ui.helper ),
   2075 			o = instance.options;
   2076 		if ( t.css( "opacity" ) ) {
   2077 			o._opacity = t.css( "opacity" );
   2078 		}
   2079 		t.css( "opacity", o.opacity );
   2080 	},
   2081 	stop: function( event, ui, instance ) {
   2082 		var o = instance.options;
   2083 		if ( o._opacity ) {
   2084 			$( ui.helper ).css( "opacity", o._opacity );
   2085 		}
   2086 	}
   2087 } );
   2088 
   2089 $.ui.plugin.add( "draggable", "scroll", {
   2090 	start: function( event, ui, i ) {
   2091 		if ( !i.scrollParentNotHidden ) {
   2092 			i.scrollParentNotHidden = i.helper.scrollParent( false );
   2093 		}
   2094 
   2095 		if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] &&
   2096 				i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) {
   2097 			i.overflowOffset = i.scrollParentNotHidden.offset();
   2098 		}
   2099 	},
   2100 	drag: function( event, ui, i  ) {
   2101 
   2102 		var o = i.options,
   2103 			scrolled = false,
   2104 			scrollParent = i.scrollParentNotHidden[ 0 ],
   2105 			document = i.document[ 0 ];
   2106 
   2107 		if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) {
   2108 			if ( !o.axis || o.axis !== "x" ) {
   2109 				if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY <
   2110 						o.scrollSensitivity ) {
   2111 					scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed;
   2112 				} else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) {
   2113 					scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed;
   2114 				}
   2115 			}
   2116 
   2117 			if ( !o.axis || o.axis !== "y" ) {
   2118 				if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX <
   2119 						o.scrollSensitivity ) {
   2120 					scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed;
   2121 				} else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) {
   2122 					scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed;
   2123 				}
   2124 			}
   2125 
   2126 		} else {
   2127 
   2128 			if ( !o.axis || o.axis !== "x" ) {
   2129 				if ( event.pageY - $( document ).scrollTop() < o.scrollSensitivity ) {
   2130 					scrolled = $( document ).scrollTop( $( document ).scrollTop() - o.scrollSpeed );
   2131 				} else if ( $( window ).height() - ( event.pageY - $( document ).scrollTop() ) <
   2132 						o.scrollSensitivity ) {
   2133 					scrolled = $( document ).scrollTop( $( document ).scrollTop() + o.scrollSpeed );
   2134 				}
   2135 			}
   2136 
   2137 			if ( !o.axis || o.axis !== "y" ) {
   2138 				if ( event.pageX - $( document ).scrollLeft() < o.scrollSensitivity ) {
   2139 					scrolled = $( document ).scrollLeft(
   2140 						$( document ).scrollLeft() - o.scrollSpeed
   2141 					);
   2142 				} else if ( $( window ).width() - ( event.pageX - $( document ).scrollLeft() ) <
   2143 						o.scrollSensitivity ) {
   2144 					scrolled = $( document ).scrollLeft(
   2145 						$( document ).scrollLeft() + o.scrollSpeed
   2146 					);
   2147 				}
   2148 			}
   2149 
   2150 		}
   2151 
   2152 		if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) {
   2153 			$.ui.ddmanager.prepareOffsets( i, event );
   2154 		}
   2155 
   2156 	}
   2157 } );
   2158 
   2159 $.ui.plugin.add( "draggable", "snap", {
   2160 	start: function( event, ui, i ) {
   2161 
   2162 		var o = i.options;
   2163 
   2164 		i.snapElements = [];
   2165 
   2166 		$( o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap )
   2167 			.each( function() {
   2168 				var $t = $( this ),
   2169 					$o = $t.offset();
   2170 				if ( this !== i.element[ 0 ] ) {
   2171 					i.snapElements.push( {
   2172 						item: this,
   2173 						width: $t.outerWidth(), height: $t.outerHeight(),
   2174 						top: $o.top, left: $o.left
   2175 					} );
   2176 				}
   2177 			} );
   2178 
   2179 	},
   2180 	drag: function( event, ui, inst ) {
   2181 
   2182 		var ts, bs, ls, rs, l, r, t, b, i, first,
   2183 			o = inst.options,
   2184 			d = o.snapTolerance,
   2185 			x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
   2186 			y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
   2187 
   2188 		for ( i = inst.snapElements.length - 1; i >= 0; i-- ) {
   2189 
   2190 			l = inst.snapElements[ i ].left - inst.margins.left;
   2191 			r = l + inst.snapElements[ i ].width;
   2192 			t = inst.snapElements[ i ].top - inst.margins.top;
   2193 			b = t + inst.snapElements[ i ].height;
   2194 
   2195 			if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d ||
   2196 					!$.contains( inst.snapElements[ i ].item.ownerDocument,
   2197 					inst.snapElements[ i ].item ) ) {
   2198 				if ( inst.snapElements[ i ].snapping ) {
   2199 					( inst.options.snap.release &&
   2200 						inst.options.snap.release.call(
   2201 							inst.element,
   2202 							event,
   2203 							$.extend( inst._uiHash(), { snapItem: inst.snapElements[ i ].item } )
   2204 						) );
   2205 				}
   2206 				inst.snapElements[ i ].snapping = false;
   2207 				continue;
   2208 			}
   2209 
   2210 			if ( o.snapMode !== "inner" ) {
   2211 				ts = Math.abs( t - y2 ) <= d;
   2212 				bs = Math.abs( b - y1 ) <= d;
   2213 				ls = Math.abs( l - x2 ) <= d;
   2214 				rs = Math.abs( r - x1 ) <= d;
   2215 				if ( ts ) {
   2216 					ui.position.top = inst._convertPositionTo( "relative", {
   2217 						top: t - inst.helperProportions.height,
   2218 						left: 0
   2219 					} ).top;
   2220 				}
   2221 				if ( bs ) {
   2222 					ui.position.top = inst._convertPositionTo( "relative", {
   2223 						top: b,
   2224 						left: 0
   2225 					} ).top;
   2226 				}
   2227 				if ( ls ) {
   2228 					ui.position.left = inst._convertPositionTo( "relative", {
   2229 						top: 0,
   2230 						left: l - inst.helperProportions.width
   2231 					} ).left;
   2232 				}
   2233 				if ( rs ) {
   2234 					ui.position.left = inst._convertPositionTo( "relative", {
   2235 						top: 0,
   2236 						left: r
   2237 					} ).left;
   2238 				}
   2239 			}
   2240 
   2241 			first = ( ts || bs || ls || rs );
   2242 
   2243 			if ( o.snapMode !== "outer" ) {
   2244 				ts = Math.abs( t - y1 ) <= d;
   2245 				bs = Math.abs( b - y2 ) <= d;
   2246 				ls = Math.abs( l - x1 ) <= d;
   2247 				rs = Math.abs( r - x2 ) <= d;
   2248 				if ( ts ) {
   2249 					ui.position.top = inst._convertPositionTo( "relative", {
   2250 						top: t,
   2251 						left: 0
   2252 					} ).top;
   2253 				}
   2254 				if ( bs ) {
   2255 					ui.position.top = inst._convertPositionTo( "relative", {
   2256 						top: b - inst.helperProportions.height,
   2257 						left: 0
   2258 					} ).top;
   2259 				}
   2260 				if ( ls ) {
   2261 					ui.position.left = inst._convertPositionTo( "relative", {
   2262 						top: 0,
   2263 						left: l
   2264 					} ).left;
   2265 				}
   2266 				if ( rs ) {
   2267 					ui.position.left = inst._convertPositionTo( "relative", {
   2268 						top: 0,
   2269 						left: r - inst.helperProportions.width
   2270 					} ).left;
   2271 				}
   2272 			}
   2273 
   2274 			if ( !inst.snapElements[ i ].snapping && ( ts || bs || ls || rs || first ) ) {
   2275 				( inst.options.snap.snap &&
   2276 					inst.options.snap.snap.call(
   2277 						inst.element,
   2278 						event,
   2279 						$.extend( inst._uiHash(), {
   2280 							snapItem: inst.snapElements[ i ].item
   2281 						} ) ) );
   2282 			}
   2283 			inst.snapElements[ i ].snapping = ( ts || bs || ls || rs || first );
   2284 
   2285 		}
   2286 
   2287 	}
   2288 } );
   2289 
   2290 $.ui.plugin.add( "draggable", "stack", {
   2291 	start: function( event, ui, instance ) {
   2292 		var min,
   2293 			o = instance.options,
   2294 			group = $.makeArray( $( o.stack ) ).sort( function( a, b ) {
   2295 				return ( parseInt( $( a ).css( "zIndex" ), 10 ) || 0 ) -
   2296 					( parseInt( $( b ).css( "zIndex" ), 10 ) || 0 );
   2297 			} );
   2298 
   2299 		if ( !group.length ) { return; }
   2300 
   2301 		min = parseInt( $( group[ 0 ] ).css( "zIndex" ), 10 ) || 0;
   2302 		$( group ).each( function( i ) {
   2303 			$( this ).css( "zIndex", min + i );
   2304 		} );
   2305 		this.css( "zIndex", ( min + group.length ) );
   2306 	}
   2307 } );
   2308 
   2309 $.ui.plugin.add( "draggable", "zIndex", {
   2310 	start: function( event, ui, instance ) {
   2311 		var t = $( ui.helper ),
   2312 			o = instance.options;
   2313 
   2314 		if ( t.css( "zIndex" ) ) {
   2315 			o._zIndex = t.css( "zIndex" );
   2316 		}
   2317 		t.css( "zIndex", o.zIndex );
   2318 	},
   2319 	stop: function( event, ui, instance ) {
   2320 		var o = instance.options;
   2321 
   2322 		if ( o._zIndex ) {
   2323 			$( ui.helper ).css( "zIndex", o._zIndex );
   2324 		}
   2325 	}
   2326 } );
   2327 
   2328 var widgetsDraggable = $.ui.draggable;
   2329 
   2330 
   2331 /*!
   2332  * jQuery UI Droppable 1.12.1
   2333  * http://jqueryui.com
   2334  *
   2335  * Copyright jQuery Foundation and other contributors
   2336  * Released under the MIT license.
   2337  * http://jquery.org/license
   2338  */
   2339 
   2340 //>>label: Droppable
   2341 //>>group: Interactions
   2342 //>>description: Enables drop targets for draggable elements.
   2343 //>>docs: http://api.jqueryui.com/droppable/
   2344 //>>demos: http://jqueryui.com/droppable/
   2345 
   2346 
   2347 
   2348 $.widget( "ui.droppable", {
   2349 	version: "1.12.1",
   2350 	widgetEventPrefix: "drop",
   2351 	options: {
   2352 		accept: "*",
   2353 		addClasses: true,
   2354 		greedy: false,
   2355 		scope: "default",
   2356 		tolerance: "intersect",
   2357 
   2358 		// Callbacks
   2359 		activate: null,
   2360 		deactivate: null,
   2361 		drop: null,
   2362 		out: null,
   2363 		over: null
   2364 	},
   2365 	_create: function() {
   2366 
   2367 		var proportions,
   2368 			o = this.options,
   2369 			accept = o.accept;
   2370 
   2371 		this.isover = false;
   2372 		this.isout = true;
   2373 
   2374 		this.accept = $.isFunction( accept ) ? accept : function( d ) {
   2375 			return d.is( accept );
   2376 		};
   2377 
   2378 		this.proportions = function( /* valueToWrite */ ) {
   2379 			if ( arguments.length ) {
   2380 
   2381 				// Store the droppable's proportions
   2382 				proportions = arguments[ 0 ];
   2383 			} else {
   2384 
   2385 				// Retrieve or derive the droppable's proportions
   2386 				return proportions ?
   2387 					proportions :
   2388 					proportions = {
   2389 						width: this.element[ 0 ].offsetWidth,
   2390 						height: this.element[ 0 ].offsetHeight
   2391 					};
   2392 			}
   2393 		};
   2394 
   2395 		this._addToManager( o.scope );
   2396 
   2397 		o.addClasses && this._addClass( "ui-droppable" );
   2398 
   2399 	},
   2400 
   2401 	_addToManager: function( scope ) {
   2402 
   2403 		// Add the reference and positions to the manager
   2404 		$.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || [];
   2405 		$.ui.ddmanager.droppables[ scope ].push( this );
   2406 	},
   2407 
   2408 	_splice: function( drop ) {
   2409 		var i = 0;
   2410 		for ( ; i < drop.length; i++ ) {
   2411 			if ( drop[ i ] === this ) {
   2412 				drop.splice( i, 1 );
   2413 			}
   2414 		}
   2415 	},
   2416 
   2417 	_destroy: function() {
   2418 		var drop = $.ui.ddmanager.droppables[ this.options.scope ];
   2419 
   2420 		this._splice( drop );
   2421 	},
   2422 
   2423 	_setOption: function( key, value ) {
   2424 
   2425 		if ( key === "accept" ) {
   2426 			this.accept = $.isFunction( value ) ? value : function( d ) {
   2427 				return d.is( value );
   2428 			};
   2429 		} else if ( key === "scope" ) {
   2430 			var drop = $.ui.ddmanager.droppables[ this.options.scope ];
   2431 
   2432 			this._splice( drop );
   2433 			this._addToManager( value );
   2434 		}
   2435 
   2436 		this._super( key, value );
   2437 	},
   2438 
   2439 	_activate: function( event ) {
   2440 		var draggable = $.ui.ddmanager.current;
   2441 
   2442 		this._addActiveClass();
   2443 		if ( draggable ) {
   2444 			this._trigger( "activate", event, this.ui( draggable ) );
   2445 		}
   2446 	},
   2447 
   2448 	_deactivate: function( event ) {
   2449 		var draggable = $.ui.ddmanager.current;
   2450 
   2451 		this._removeActiveClass();
   2452 		if ( draggable ) {
   2453 			this._trigger( "deactivate", event, this.ui( draggable ) );
   2454 		}
   2455 	},
   2456 
   2457 	_over: function( event ) {
   2458 
   2459 		var draggable = $.ui.ddmanager.current;
   2460 
   2461 		// Bail if draggable and droppable are same element
   2462 		if ( !draggable || ( draggable.currentItem ||
   2463 				draggable.element )[ 0 ] === this.element[ 0 ] ) {
   2464 			return;
   2465 		}
   2466 
   2467 		if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem ||
   2468 				draggable.element ) ) ) {
   2469 			this._addHoverClass();
   2470 			this._trigger( "over", event, this.ui( draggable ) );
   2471 		}
   2472 
   2473 	},
   2474 
   2475 	_out: function( event ) {
   2476 
   2477 		var draggable = $.ui.ddmanager.current;
   2478 
   2479 		// Bail if draggable and droppable are same element
   2480 		if ( !draggable || ( draggable.currentItem ||
   2481 				draggable.element )[ 0 ] === this.element[ 0 ] ) {
   2482 			return;
   2483 		}
   2484 
   2485 		if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem ||
   2486 				draggable.element ) ) ) {
   2487 			this._removeHoverClass();
   2488 			this._trigger( "out", event, this.ui( draggable ) );
   2489 		}
   2490 
   2491 	},
   2492 
   2493 	_drop: function( event, custom ) {
   2494 
   2495 		var draggable = custom || $.ui.ddmanager.current,
   2496 			childrenIntersection = false;
   2497 
   2498 		// Bail if draggable and droppable are same element
   2499 		if ( !draggable || ( draggable.currentItem ||
   2500 				draggable.element )[ 0 ] === this.element[ 0 ] ) {
   2501 			return false;
   2502 		}
   2503 
   2504 		this.element
   2505 			.find( ":data(ui-droppable)" )
   2506 			.not( ".ui-draggable-dragging" )
   2507 			.each( function() {
   2508 				var inst = $( this ).droppable( "instance" );
   2509 				if (
   2510 					inst.options.greedy &&
   2511 					!inst.options.disabled &&
   2512 					inst.options.scope === draggable.options.scope &&
   2513 					inst.accept.call(
   2514 						inst.element[ 0 ], ( draggable.currentItem || draggable.element )
   2515 					) &&
   2516 					intersect(
   2517 						draggable,
   2518 						$.extend( inst, { offset: inst.element.offset() } ),
   2519 						inst.options.tolerance, event
   2520 					)
   2521 				) {
   2522 					childrenIntersection = true;
   2523 					return false; }
   2524 			} );
   2525 		if ( childrenIntersection ) {
   2526 			return false;
   2527 		}
   2528 
   2529 		if ( this.accept.call( this.element[ 0 ],
   2530 				( draggable.currentItem || draggable.element ) ) ) {
   2531 			this._removeActiveClass();
   2532 			this._removeHoverClass();
   2533 
   2534 			this._trigger( "drop", event, this.ui( draggable ) );
   2535 			return this.element;
   2536 		}
   2537 
   2538 		return false;
   2539 
   2540 	},
   2541 
   2542 	ui: function( c ) {
   2543 		return {
   2544 			draggable: ( c.currentItem || c.element ),
   2545 			helper: c.helper,
   2546 			position: c.position,
   2547 			offset: c.positionAbs
   2548 		};
   2549 	},
   2550 
   2551 	// Extension points just to make backcompat sane and avoid duplicating logic
   2552 	// TODO: Remove in 1.13 along with call to it below
   2553 	_addHoverClass: function() {
   2554 		this._addClass( "ui-droppable-hover" );
   2555 	},
   2556 
   2557 	_removeHoverClass: function() {
   2558 		this._removeClass( "ui-droppable-hover" );
   2559 	},
   2560 
   2561 	_addActiveClass: function() {
   2562 		this._addClass( "ui-droppable-active" );
   2563 	},
   2564 
   2565 	_removeActiveClass: function() {
   2566 		this._removeClass( "ui-droppable-active" );
   2567 	}
   2568 } );
   2569 
   2570 var intersect = $.ui.intersect = ( function() {
   2571 	function isOverAxis( x, reference, size ) {
   2572 		return ( x >= reference ) && ( x < ( reference + size ) );
   2573 	}
   2574 
   2575 	return function( draggable, droppable, toleranceMode, event ) {
   2576 
   2577 		if ( !droppable.offset ) {
   2578 			return false;
   2579 		}
   2580 
   2581 		var x1 = ( draggable.positionAbs ||
   2582 				draggable.position.absolute ).left + draggable.margins.left,
   2583 			y1 = ( draggable.positionAbs ||
   2584 				draggable.position.absolute ).top + draggable.margins.top,
   2585 			x2 = x1 + draggable.helperProportions.width,
   2586 			y2 = y1 + draggable.helperProportions.height,
   2587 			l = droppable.offset.left,
   2588 			t = droppable.offset.top,
   2589 			r = l + droppable.proportions().width,
   2590 			b = t + droppable.proportions().height;
   2591 
   2592 		switch ( toleranceMode ) {
   2593 		case "fit":
   2594 			return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b );
   2595 		case "intersect":
   2596 			return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half
   2597 				x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half
   2598 				t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half
   2599 				y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half
   2600 		case "pointer":
   2601 			return isOverAxis( event.pageY, t, droppable.proportions().height ) &&
   2602 				isOverAxis( event.pageX, l, droppable.proportions().width );
   2603 		case "touch":
   2604 			return (
   2605 				( y1 >= t && y1 <= b ) || // Top edge touching
   2606 				( y2 >= t && y2 <= b ) || // Bottom edge touching
   2607 				( y1 < t && y2 > b ) // Surrounded vertically
   2608 			) && (
   2609 				( x1 >= l && x1 <= r ) || // Left edge touching
   2610 				( x2 >= l && x2 <= r ) || // Right edge touching
   2611 				( x1 < l && x2 > r ) // Surrounded horizontally
   2612 			);
   2613 		default:
   2614 			return false;
   2615 		}
   2616 	};
   2617 } )();
   2618 
   2619 /*
   2620 	This manager tracks offsets of draggables and droppables
   2621 */
   2622 $.ui.ddmanager = {
   2623 	current: null,
   2624 	droppables: { "default": [] },
   2625 	prepareOffsets: function( t, event ) {
   2626 
   2627 		var i, j,
   2628 			m = $.ui.ddmanager.droppables[ t.options.scope ] || [],
   2629 			type = event ? event.type : null, // workaround for #2317
   2630 			list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack();
   2631 
   2632 		droppablesLoop: for ( i = 0; i < m.length; i++ ) {
   2633 
   2634 			// No disabled and non-accepted
   2635 			if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ],
   2636 					( t.currentItem || t.element ) ) ) ) {
   2637 				continue;
   2638 			}
   2639 
   2640 			// Filter out elements in the current dragged item
   2641 			for ( j = 0; j < list.length; j++ ) {
   2642 				if ( list[ j ] === m[ i ].element[ 0 ] ) {
   2643 					m[ i ].proportions().height = 0;
   2644 					continue droppablesLoop;
   2645 				}
   2646 			}
   2647 
   2648 			m[ i ].visible = m[ i ].element.css( "display" ) !== "none";
   2649 			if ( !m[ i ].visible ) {
   2650 				continue;
   2651 			}
   2652 
   2653 			// Activate the droppable if used directly from draggables
   2654 			if ( type === "mousedown" ) {
   2655 				m[ i ]._activate.call( m[ i ], event );
   2656 			}
   2657 
   2658 			m[ i ].offset = m[ i ].element.offset();
   2659 			m[ i ].proportions( {
   2660 				width: m[ i ].element[ 0 ].offsetWidth,
   2661 				height: m[ i ].element[ 0 ].offsetHeight
   2662 			} );
   2663 
   2664 		}
   2665 
   2666 	},
   2667 	drop: function( draggable, event ) {
   2668 
   2669 		var dropped = false;
   2670 
   2671 		// Create a copy of the droppables in case the list changes during the drop (#9116)
   2672 		$.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() {
   2673 
   2674 			if ( !this.options ) {
   2675 				return;
   2676 			}
   2677 			if ( !this.options.disabled && this.visible &&
   2678 					intersect( draggable, this, this.options.tolerance, event ) ) {
   2679 				dropped = this._drop.call( this, event ) || dropped;
   2680 			}
   2681 
   2682 			if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ],
   2683 					( draggable.currentItem || draggable.element ) ) ) {
   2684 				this.isout = true;
   2685 				this.isover = false;
   2686 				this._deactivate.call( this, event );
   2687 			}
   2688 
   2689 		} );
   2690 		return dropped;
   2691 
   2692 	},
   2693 	dragStart: function( draggable, event ) {
   2694 
   2695 		// Listen for scrolling so that if the dragging causes scrolling the position of the
   2696 		// droppables can be recalculated (see #5003)
   2697 		draggable.element.parentsUntil( "body" ).on( "scroll.droppable", function() {
   2698 			if ( !draggable.options.refreshPositions ) {
   2699 				$.ui.ddmanager.prepareOffsets( draggable, event );
   2700 			}
   2701 		} );
   2702 	},
   2703 	drag: function( draggable, event ) {
   2704 
   2705 		// If you have a highly dynamic page, you might try this option. It renders positions
   2706 		// every time you move the mouse.
   2707 		if ( draggable.options.refreshPositions ) {
   2708 			$.ui.ddmanager.prepareOffsets( draggable, event );
   2709 		}
   2710 
   2711 		// Run through all droppables and check their positions based on specific tolerance options
   2712 		$.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() {
   2713 
   2714 			if ( this.options.disabled || this.greedyChild || !this.visible ) {
   2715 				return;
   2716 			}
   2717 
   2718 			var parentInstance, scope, parent,
   2719 				intersects = intersect( draggable, this, this.options.tolerance, event ),
   2720 				c = !intersects && this.isover ?
   2721 					"isout" :
   2722 					( intersects && !this.isover ? "isover" : null );
   2723 			if ( !c ) {
   2724 				return;
   2725 			}
   2726 
   2727 			if ( this.options.greedy ) {
   2728 
   2729 				// find droppable parents with same scope
   2730 				scope = this.options.scope;
   2731 				parent = this.element.parents( ":data(ui-droppable)" ).filter( function() {
   2732 					return $( this ).droppable( "instance" ).options.scope === scope;
   2733 				} );
   2734 
   2735 				if ( parent.length ) {
   2736 					parentInstance = $( parent[ 0 ] ).droppable( "instance" );
   2737 					parentInstance.greedyChild = ( c === "isover" );
   2738 				}
   2739 			}
   2740 
   2741 			// We just moved into a greedy child
   2742 			if ( parentInstance && c === "isover" ) {
   2743 				parentInstance.isover = false;
   2744 				parentInstance.isout = true;
   2745 				parentInstance._out.call( parentInstance, event );
   2746 			}
   2747 
   2748 			this[ c ] = true;
   2749 			this[ c === "isout" ? "isover" : "isout" ] = false;
   2750 			this[ c === "isover" ? "_over" : "_out" ].call( this, event );
   2751 
   2752 			// We just moved out of a greedy child
   2753 			if ( parentInstance && c === "isout" ) {
   2754 				parentInstance.isout = false;
   2755 				parentInstance.isover = true;
   2756 				parentInstance._over.call( parentInstance, event );
   2757 			}
   2758 		} );
   2759 
   2760 	},
   2761 	dragStop: function( draggable, event ) {
   2762 		draggable.element.parentsUntil( "body" ).off( "scroll.droppable" );
   2763 
   2764 		// Call prepareOffsets one final time since IE does not fire return scroll events when
   2765 		// overflow was caused by drag (see #5003)
   2766 		if ( !draggable.options.refreshPositions ) {
   2767 			$.ui.ddmanager.prepareOffsets( draggable, event );
   2768 		}
   2769 	}
   2770 };
   2771 
   2772 // DEPRECATED
   2773 // TODO: switch return back to widget declaration at top of file when this is removed
   2774 if ( $.uiBackCompat !== false ) {
   2775 
   2776 	// Backcompat for activeClass and hoverClass options
   2777 	$.widget( "ui.droppable", $.ui.droppable, {
   2778 		options: {
   2779 			hoverClass: false,
   2780 			activeClass: false
   2781 		},
   2782 		_addActiveClass: function() {
   2783 			this._super();
   2784 			if ( this.options.activeClass ) {
   2785 				this.element.addClass( this.options.activeClass );
   2786 			}
   2787 		},
   2788 		_removeActiveClass: function() {
   2789 			this._super();
   2790 			if ( this.options.activeClass ) {
   2791 				this.element.removeClass( this.options.activeClass );
   2792 			}
   2793 		},
   2794 		_addHoverClass: function() {
   2795 			this._super();
   2796 			if ( this.options.hoverClass ) {
   2797 				this.element.addClass( this.options.hoverClass );
   2798 			}
   2799 		},
   2800 		_removeHoverClass: function() {
   2801 			this._super();
   2802 			if ( this.options.hoverClass ) {
   2803 				this.element.removeClass( this.options.hoverClass );
   2804 			}
   2805 		}
   2806 	} );
   2807 }
   2808 
   2809 var widgetsDroppable = $.ui.droppable;
   2810 
   2811 
   2812 /*!
   2813  * jQuery UI Sortable 1.12.1
   2814  * http://jqueryui.com
   2815  *
   2816  * Copyright jQuery Foundation and other contributors
   2817  * Released under the MIT license.
   2818  * http://jquery.org/license
   2819  */
   2820 
   2821 //>>label: Sortable
   2822 //>>group: Interactions
   2823 //>>description: Enables items in a list to be sorted using the mouse.
   2824 //>>docs: http://api.jqueryui.com/sortable/
   2825 //>>demos: http://jqueryui.com/sortable/
   2826 //>>css.structure: ../../themes/base/sortable.css
   2827 
   2828 
   2829 
   2830 var widgetsSortable = $.widget( "ui.sortable", $.ui.mouse, {
   2831 	version: "1.12.1",
   2832 	widgetEventPrefix: "sort",
   2833 	ready: false,
   2834 	options: {
   2835 		appendTo: "parent",
   2836 		axis: false,
   2837 		connectWith: false,
   2838 		containment: false,
   2839 		cursor: "auto",
   2840 		cursorAt: false,
   2841 		dropOnEmpty: true,
   2842 		forcePlaceholderSize: false,
   2843 		forceHelperSize: false,
   2844 		grid: false,
   2845 		handle: false,
   2846 		helper: "original",
   2847 		items: "> *",
   2848 		opacity: false,
   2849 		placeholder: false,
   2850 		revert: false,
   2851 		scroll: true,
   2852 		scrollSensitivity: 20,
   2853 		scrollSpeed: 20,
   2854 		scope: "default",
   2855 		tolerance: "intersect",
   2856 		zIndex: 1000,
   2857 
   2858 		// Callbacks
   2859 		activate: null,
   2860 		beforeStop: null,
   2861 		change: null,
   2862 		deactivate: null,
   2863 		out: null,
   2864 		over: null,
   2865 		receive: null,
   2866 		remove: null,
   2867 		sort: null,
   2868 		start: null,
   2869 		stop: null,
   2870 		update: null
   2871 	},
   2872 
   2873 	_isOverAxis: function( x, reference, size ) {
   2874 		return ( x >= reference ) && ( x < ( reference + size ) );
   2875 	},
   2876 
   2877 	_isFloating: function( item ) {
   2878 		return ( /left|right/ ).test( item.css( "float" ) ) ||
   2879 			( /inline|table-cell/ ).test( item.css( "display" ) );
   2880 	},
   2881 
   2882 	_create: function() {
   2883 		this.containerCache = {};
   2884 		this._addClass( "ui-sortable" );
   2885 
   2886 		//Get the items
   2887 		this.refresh();
   2888 
   2889 		//Let's determine the parent's offset
   2890 		this.offset = this.element.offset();
   2891 
   2892 		//Initialize mouse events for interaction
   2893 		this._mouseInit();
   2894 
   2895 		this._setHandleClassName();
   2896 
   2897 		//We're ready to go
   2898 		this.ready = true;
   2899 
   2900 	},
   2901 
   2902 	_setOption: function( key, value ) {
   2903 		this._super( key, value );
   2904 
   2905 		if ( key === "handle" ) {
   2906 			this._setHandleClassName();
   2907 		}
   2908 	},
   2909 
   2910 	_setHandleClassName: function() {
   2911 		var that = this;
   2912 		this._removeClass( this.element.find( ".ui-sortable-handle" ), "ui-sortable-handle" );
   2913 		$.each( this.items, function() {
   2914 			that._addClass(
   2915 				this.instance.options.handle ?
   2916 					this.item.find( this.instance.options.handle ) :
   2917 					this.item,
   2918 				"ui-sortable-handle"
   2919 			);
   2920 		} );
   2921 	},
   2922 
   2923 	_destroy: function() {
   2924 		this._mouseDestroy();
   2925 
   2926 		for ( var i = this.items.length - 1; i >= 0; i-- ) {
   2927 			this.items[ i ].item.removeData( this.widgetName + "-item" );
   2928 		}
   2929 
   2930 		return this;
   2931 	},
   2932 
   2933 	_mouseCapture: function( event, overrideHandle ) {
   2934 		var currentItem = null,
   2935 			validHandle = false,
   2936 			that = this;
   2937 
   2938 		if ( this.reverting ) {
   2939 			return false;
   2940 		}
   2941 
   2942 		if ( this.options.disabled || this.options.type === "static" ) {
   2943 			return false;
   2944 		}
   2945 
   2946 		//We have to refresh the items data once first
   2947 		this._refreshItems( event );
   2948 
   2949 		//Find out if the clicked node (or one of its parents) is a actual item in this.items
   2950 		$( event.target ).parents().each( function() {
   2951 			if ( $.data( this, that.widgetName + "-item" ) === that ) {
   2952 				currentItem = $( this );
   2953 				return false;
   2954 			}
   2955 		} );
   2956 		if ( $.data( event.target, that.widgetName + "-item" ) === that ) {
   2957 			currentItem = $( event.target );
   2958 		}
   2959 
   2960 		if ( !currentItem ) {
   2961 			return false;
   2962 		}
   2963 		if ( this.options.handle && !overrideHandle ) {
   2964 			$( this.options.handle, currentItem ).find( "*" ).addBack().each( function() {
   2965 				if ( this === event.target ) {
   2966 					validHandle = true;
   2967 				}
   2968 			} );
   2969 			if ( !validHandle ) {
   2970 				return false;
   2971 			}
   2972 		}
   2973 
   2974 		this.currentItem = currentItem;
   2975 		this._removeCurrentsFromItems();
   2976 		return true;
   2977 
   2978 	},
   2979 
   2980 	_mouseStart: function( event, overrideHandle, noActivation ) {
   2981 
   2982 		var i, body,
   2983 			o = this.options;
   2984 
   2985 		this.currentContainer = this;
   2986 
   2987 		//We only need to call refreshPositions, because the refreshItems call has been moved to
   2988 		// mouseCapture
   2989 		this.refreshPositions();
   2990 
   2991 		//Create and append the visible helper
   2992 		this.helper = this._createHelper( event );
   2993 
   2994 		//Cache the helper size
   2995 		this._cacheHelperProportions();
   2996 
   2997 		/*
   2998 		 * - Position generation -
   2999 		 * This block generates everything position related - it's the core of draggables.
   3000 		 */
   3001 
   3002 		//Cache the margins of the original element
   3003 		this._cacheMargins();
   3004 
   3005 		//Get the next scrolling parent
   3006 		this.scrollParent = this.helper.scrollParent();
   3007 
   3008 		//The element's absolute position on the page minus margins
   3009 		this.offset = this.currentItem.offset();
   3010 		this.offset = {
   3011 			top: this.offset.top - this.margins.top,
   3012 			left: this.offset.left - this.margins.left
   3013 		};
   3014 
   3015 		$.extend( this.offset, {
   3016 			click: { //Where the click happened, relative to the element
   3017 				left: event.pageX - this.offset.left,
   3018 				top: event.pageY - this.offset.top
   3019 			},
   3020 			parent: this._getParentOffset(),
   3021 
   3022 			// This is a relative to absolute position minus the actual position calculation -
   3023 			// only used for relative positioned helper
   3024 			relative: this._getRelativeOffset()
   3025 		} );
   3026 
   3027 		// Only after we got the offset, we can change the helper's position to absolute
   3028 		// TODO: Still need to figure out a way to make relative sorting possible
   3029 		this.helper.css( "position", "absolute" );
   3030 		this.cssPosition = this.helper.css( "position" );
   3031 
   3032 		//Generate the original position
   3033 		this.originalPosition = this._generatePosition( event );
   3034 		this.originalPageX = event.pageX;
   3035 		this.originalPageY = event.pageY;
   3036 
   3037 		//Adjust the mouse offset relative to the helper if "cursorAt" is supplied
   3038 		( o.cursorAt && this._adjustOffsetFromHelper( o.cursorAt ) );
   3039 
   3040 		//Cache the former DOM position
   3041 		this.domPosition = {
   3042 			prev: this.currentItem.prev()[ 0 ],
   3043 			parent: this.currentItem.parent()[ 0 ]
   3044 		};
   3045 
   3046 		// If the helper is not the original, hide the original so it's not playing any role during
   3047 		// the drag, won't cause anything bad this way
   3048 		if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
   3049 			this.currentItem.hide();
   3050 		}
   3051 
   3052 		//Create the placeholder
   3053 		this._createPlaceholder();
   3054 
   3055 		//Set a containment if given in the options
   3056 		if ( o.containment ) {
   3057 			this._setContainment();
   3058 		}
   3059 
   3060 		if ( o.cursor && o.cursor !== "auto" ) { // cursor option
   3061 			body = this.document.find( "body" );
   3062 
   3063 			// Support: IE
   3064 			this.storedCursor = body.css( "cursor" );
   3065 			body.css( "cursor", o.cursor );
   3066 
   3067 			this.storedStylesheet =
   3068 				$( "<style>*{ cursor: " + o.cursor + " !important; }</style>" ).appendTo( body );
   3069 		}
   3070 
   3071 		if ( o.opacity ) { // opacity option
   3072 			if ( this.helper.css( "opacity" ) ) {
   3073 				this._storedOpacity = this.helper.css( "opacity" );
   3074 			}
   3075 			this.helper.css( "opacity", o.opacity );
   3076 		}
   3077 
   3078 		if ( o.zIndex ) { // zIndex option
   3079 			if ( this.helper.css( "zIndex" ) ) {
   3080 				this._storedZIndex = this.helper.css( "zIndex" );
   3081 			}
   3082 			this.helper.css( "zIndex", o.zIndex );
   3083 		}
   3084 
   3085 		//Prepare scrolling
   3086 		if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
   3087 				this.scrollParent[ 0 ].tagName !== "HTML" ) {
   3088 			this.overflowOffset = this.scrollParent.offset();
   3089 		}
   3090 
   3091 		//Call callbacks
   3092 		this._trigger( "start", event, this._uiHash() );
   3093 
   3094 		//Recache the helper size
   3095 		if ( !this._preserveHelperProportions ) {
   3096 			this._cacheHelperProportions();
   3097 		}
   3098 
   3099 		//Post "activate" events to possible containers
   3100 		if ( !noActivation ) {
   3101 			for ( i = this.containers.length - 1; i >= 0; i-- ) {
   3102 				this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
   3103 			}
   3104 		}
   3105 
   3106 		//Prepare possible droppables
   3107 		if ( $.ui.ddmanager ) {
   3108 			$.ui.ddmanager.current = this;
   3109 		}
   3110 
   3111 		if ( $.ui.ddmanager && !o.dropBehaviour ) {
   3112 			$.ui.ddmanager.prepareOffsets( this, event );
   3113 		}
   3114 
   3115 		this.dragging = true;
   3116 
   3117 		this._addClass( this.helper, "ui-sortable-helper" );
   3118 
   3119 		// Execute the drag once - this causes the helper not to be visiblebefore getting its
   3120 		// correct position
   3121 		this._mouseDrag( event );
   3122 		return true;
   3123 
   3124 	},
   3125 
   3126 	_mouseDrag: function( event ) {
   3127 		var i, item, itemElement, intersection,
   3128 			o = this.options,
   3129 			scrolled = false;
   3130 
   3131 		//Compute the helpers position
   3132 		this.position = this._generatePosition( event );
   3133 		this.positionAbs = this._convertPositionTo( "absolute" );
   3134 
   3135 		if ( !this.lastPositionAbs ) {
   3136 			this.lastPositionAbs = this.positionAbs;
   3137 		}
   3138 
   3139 		//Do scrolling
   3140 		if ( this.options.scroll ) {
   3141 			if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
   3142 					this.scrollParent[ 0 ].tagName !== "HTML" ) {
   3143 
   3144 				if ( ( this.overflowOffset.top + this.scrollParent[ 0 ].offsetHeight ) -
   3145 						event.pageY < o.scrollSensitivity ) {
   3146 					this.scrollParent[ 0 ].scrollTop =
   3147 						scrolled = this.scrollParent[ 0 ].scrollTop + o.scrollSpeed;
   3148 				} else if ( event.pageY - this.overflowOffset.top < o.scrollSensitivity ) {
   3149 					this.scrollParent[ 0 ].scrollTop =
   3150 						scrolled = this.scrollParent[ 0 ].scrollTop - o.scrollSpeed;
   3151 				}
   3152 
   3153 				if ( ( this.overflowOffset.left + this.scrollParent[ 0 ].offsetWidth ) -
   3154 						event.pageX < o.scrollSensitivity ) {
   3155 					this.scrollParent[ 0 ].scrollLeft = scrolled =
   3156 						this.scrollParent[ 0 ].scrollLeft + o.scrollSpeed;
   3157 				} else if ( event.pageX - this.overflowOffset.left < o.scrollSensitivity ) {
   3158 					this.scrollParent[ 0 ].scrollLeft = scrolled =
   3159 						this.scrollParent[ 0 ].scrollLeft - o.scrollSpeed;
   3160 				}
   3161 
   3162 			} else {
   3163 
   3164 				if ( event.pageY - this.document.scrollTop() < o.scrollSensitivity ) {
   3165 					scrolled = this.document.scrollTop( this.document.scrollTop() - o.scrollSpeed );
   3166 				} else if ( this.window.height() - ( event.pageY - this.document.scrollTop() ) <
   3167 						o.scrollSensitivity ) {
   3168 					scrolled = this.document.scrollTop( this.document.scrollTop() + o.scrollSpeed );
   3169 				}
   3170 
   3171 				if ( event.pageX - this.document.scrollLeft() < o.scrollSensitivity ) {
   3172 					scrolled = this.document.scrollLeft(
   3173 						this.document.scrollLeft() - o.scrollSpeed
   3174 					);
   3175 				} else if ( this.window.width() - ( event.pageX - this.document.scrollLeft() ) <
   3176 						o.scrollSensitivity ) {
   3177 					scrolled = this.document.scrollLeft(
   3178 						this.document.scrollLeft() + o.scrollSpeed
   3179 					);
   3180 				}
   3181 
   3182 			}
   3183 
   3184 			if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) {
   3185 				$.ui.ddmanager.prepareOffsets( this, event );
   3186 			}
   3187 		}
   3188 
   3189 		//Regenerate the absolute position used for position checks
   3190 		this.positionAbs = this._convertPositionTo( "absolute" );
   3191 
   3192 		//Set the helper position
   3193 		if ( !this.options.axis || this.options.axis !== "y" ) {
   3194 			this.helper[ 0 ].style.left = this.position.left + "px";
   3195 		}
   3196 		if ( !this.options.axis || this.options.axis !== "x" ) {
   3197 			this.helper[ 0 ].style.top = this.position.top + "px";
   3198 		}
   3199 
   3200 		//Rearrange
   3201 		for ( i = this.items.length - 1; i >= 0; i-- ) {
   3202 
   3203 			//Cache variables and intersection, continue if no intersection
   3204 			item = this.items[ i ];
   3205 			itemElement = item.item[ 0 ];
   3206 			intersection = this._intersectsWithPointer( item );
   3207 			if ( !intersection ) {
   3208 				continue;
   3209 			}
   3210 
   3211 			// Only put the placeholder inside the current Container, skip all
   3212 			// items from other containers. This works because when moving
   3213 			// an item from one container to another the
   3214 			// currentContainer is switched before the placeholder is moved.
   3215 			//
   3216 			// Without this, moving items in "sub-sortables" can cause
   3217 			// the placeholder to jitter between the outer and inner container.
   3218 			if ( item.instance !== this.currentContainer ) {
   3219 				continue;
   3220 			}
   3221 
   3222 			// Cannot intersect with itself
   3223 			// no useless actions that have been done before
   3224 			// no action if the item moved is the parent of the item checked
   3225 			if ( itemElement !== this.currentItem[ 0 ] &&
   3226 				this.placeholder[ intersection === 1 ? "next" : "prev" ]()[ 0 ] !== itemElement &&
   3227 				!$.contains( this.placeholder[ 0 ], itemElement ) &&
   3228 				( this.options.type === "semi-dynamic" ?
   3229 					!$.contains( this.element[ 0 ], itemElement ) :
   3230 					true
   3231 				)
   3232 			) {
   3233 
   3234 				this.direction = intersection === 1 ? "down" : "up";
   3235 
   3236 				if ( this.options.tolerance === "pointer" || this._intersectsWithSides( item ) ) {
   3237 					this._rearrange( event, item );
   3238 				} else {
   3239 					break;
   3240 				}
   3241 
   3242 				this._trigger( "change", event, this._uiHash() );
   3243 				break;
   3244 			}
   3245 		}
   3246 
   3247 		//Post events to containers
   3248 		this._contactContainers( event );
   3249 
   3250 		//Interconnect with droppables
   3251 		if ( $.ui.ddmanager ) {
   3252 			$.ui.ddmanager.drag( this, event );
   3253 		}
   3254 
   3255 		//Call callbacks
   3256 		this._trigger( "sort", event, this._uiHash() );
   3257 
   3258 		this.lastPositionAbs = this.positionAbs;
   3259 		return false;
   3260 
   3261 	},
   3262 
   3263 	_mouseStop: function( event, noPropagation ) {
   3264 
   3265 		if ( !event ) {
   3266 			return;
   3267 		}
   3268 
   3269 		//If we are using droppables, inform the manager about the drop
   3270 		if ( $.ui.ddmanager && !this.options.dropBehaviour ) {
   3271 			$.ui.ddmanager.drop( this, event );
   3272 		}
   3273 
   3274 		if ( this.options.revert ) {
   3275 			var that = this,
   3276 				cur = this.placeholder.offset(),
   3277 				axis = this.options.axis,
   3278 				animation = {};
   3279 
   3280 			if ( !axis || axis === "x" ) {
   3281 				animation.left = cur.left - this.offset.parent.left - this.margins.left +
   3282 					( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
   3283 						0 :
   3284 						this.offsetParent[ 0 ].scrollLeft
   3285 					);
   3286 			}
   3287 			if ( !axis || axis === "y" ) {
   3288 				animation.top = cur.top - this.offset.parent.top - this.margins.top +
   3289 					( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
   3290 						0 :
   3291 						this.offsetParent[ 0 ].scrollTop
   3292 					);
   3293 			}
   3294 			this.reverting = true;
   3295 			$( this.helper ).animate(
   3296 				animation,
   3297 				parseInt( this.options.revert, 10 ) || 500,
   3298 				function() {
   3299 					that._clear( event );
   3300 				}
   3301 			);
   3302 		} else {
   3303 			this._clear( event, noPropagation );
   3304 		}
   3305 
   3306 		return false;
   3307 
   3308 	},
   3309 
   3310 	cancel: function() {
   3311 
   3312 		if ( this.dragging ) {
   3313 
   3314 			this._mouseUp( new $.Event( "mouseup", { target: null } ) );
   3315 
   3316 			if ( this.options.helper === "original" ) {
   3317 				this.currentItem.css( this._storedCSS );
   3318 				this._removeClass( this.currentItem, "ui-sortable-helper" );
   3319 			} else {
   3320 				this.currentItem.show();
   3321 			}
   3322 
   3323 			//Post deactivating events to containers
   3324 			for ( var i = this.containers.length - 1; i >= 0; i-- ) {
   3325 				this.containers[ i ]._trigger( "deactivate", null, this._uiHash( this ) );
   3326 				if ( this.containers[ i ].containerCache.over ) {
   3327 					this.containers[ i ]._trigger( "out", null, this._uiHash( this ) );
   3328 					this.containers[ i ].containerCache.over = 0;
   3329 				}
   3330 			}
   3331 
   3332 		}
   3333 
   3334 		if ( this.placeholder ) {
   3335 
   3336 			//$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
   3337 			// it unbinds ALL events from the original node!
   3338 			if ( this.placeholder[ 0 ].parentNode ) {
   3339 				this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );
   3340 			}
   3341 			if ( this.options.helper !== "original" && this.helper &&
   3342 					this.helper[ 0 ].parentNode ) {
   3343 				this.helper.remove();
   3344 			}
   3345 
   3346 			$.extend( this, {
   3347 				helper: null,
   3348 				dragging: false,
   3349 				reverting: false,
   3350 				_noFinalSort: null
   3351 			} );
   3352 
   3353 			if ( this.domPosition.prev ) {
   3354 				$( this.domPosition.prev ).after( this.currentItem );
   3355 			} else {
   3356 				$( this.domPosition.parent ).prepend( this.currentItem );
   3357 			}
   3358 		}
   3359 
   3360 		return this;
   3361 
   3362 	},
   3363 
   3364 	serialize: function( o ) {
   3365 
   3366 		var items = this._getItemsAsjQuery( o && o.connected ),
   3367 			str = [];
   3368 		o = o || {};
   3369 
   3370 		$( items ).each( function() {
   3371 			var res = ( $( o.item || this ).attr( o.attribute || "id" ) || "" )
   3372 				.match( o.expression || ( /(.+)[\-=_](.+)/ ) );
   3373 			if ( res ) {
   3374 				str.push(
   3375 					( o.key || res[ 1 ] + "[]" ) +
   3376 					"=" + ( o.key && o.expression ? res[ 1 ] : res[ 2 ] ) );
   3377 			}
   3378 		} );
   3379 
   3380 		if ( !str.length && o.key ) {
   3381 			str.push( o.key + "=" );
   3382 		}
   3383 
   3384 		return str.join( "&" );
   3385 
   3386 	},
   3387 
   3388 	toArray: function( o ) {
   3389 
   3390 		var items = this._getItemsAsjQuery( o && o.connected ),
   3391 			ret = [];
   3392 
   3393 		o = o || {};
   3394 
   3395 		items.each( function() {
   3396 			ret.push( $( o.item || this ).attr( o.attribute || "id" ) || "" );
   3397 		} );
   3398 		return ret;
   3399 
   3400 	},
   3401 
   3402 	/* Be careful with the following core functions */
   3403 	_intersectsWith: function( item ) {
   3404 
   3405 		var x1 = this.positionAbs.left,
   3406 			x2 = x1 + this.helperProportions.width,
   3407 			y1 = this.positionAbs.top,
   3408 			y2 = y1 + this.helperProportions.height,
   3409 			l = item.left,
   3410 			r = l + item.width,
   3411 			t = item.top,
   3412 			b = t + item.height,
   3413 			dyClick = this.offset.click.top,
   3414 			dxClick = this.offset.click.left,
   3415 			isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t &&
   3416 				( y1 + dyClick ) < b ),
   3417 			isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l &&
   3418 				( x1 + dxClick ) < r ),
   3419 			isOverElement = isOverElementHeight && isOverElementWidth;
   3420 
   3421 		if ( this.options.tolerance === "pointer" ||
   3422 			this.options.forcePointerForContainers ||
   3423 			( this.options.tolerance !== "pointer" &&
   3424 				this.helperProportions[ this.floating ? "width" : "height" ] >
   3425 				item[ this.floating ? "width" : "height" ] )
   3426 		) {
   3427 			return isOverElement;
   3428 		} else {
   3429 
   3430 			return ( l < x1 + ( this.helperProportions.width / 2 ) && // Right Half
   3431 				x2 - ( this.helperProportions.width / 2 ) < r && // Left Half
   3432 				t < y1 + ( this.helperProportions.height / 2 ) && // Bottom Half
   3433 				y2 - ( this.helperProportions.height / 2 ) < b ); // Top Half
   3434 
   3435 		}
   3436 	},
   3437 
   3438 	_intersectsWithPointer: function( item ) {
   3439 		var verticalDirection, horizontalDirection,
   3440 			isOverElementHeight = ( this.options.axis === "x" ) ||
   3441 				this._isOverAxis(
   3442 					this.positionAbs.top + this.offset.click.top, item.top, item.height ),
   3443 			isOverElementWidth = ( this.options.axis === "y" ) ||
   3444 				this._isOverAxis(
   3445 					this.positionAbs.left + this.offset.click.left, item.left, item.width ),
   3446 			isOverElement = isOverElementHeight && isOverElementWidth;
   3447 
   3448 		if ( !isOverElement ) {
   3449 			return false;
   3450 		}
   3451 
   3452 		verticalDirection = this._getDragVerticalDirection();
   3453 		horizontalDirection = this._getDragHorizontalDirection();
   3454 
   3455 		return this.floating ?
   3456 			( ( horizontalDirection === "right" || verticalDirection === "down" ) ? 2 : 1 )
   3457 			: ( verticalDirection && ( verticalDirection === "down" ? 2 : 1 ) );
   3458 
   3459 	},
   3460 
   3461 	_intersectsWithSides: function( item ) {
   3462 
   3463 		var isOverBottomHalf = this._isOverAxis( this.positionAbs.top +
   3464 				this.offset.click.top, item.top + ( item.height / 2 ), item.height ),
   3465 			isOverRightHalf = this._isOverAxis( this.positionAbs.left +
   3466 				this.offset.click.left, item.left + ( item.width / 2 ), item.width ),
   3467 			verticalDirection = this._getDragVerticalDirection(),
   3468 			horizontalDirection = this._getDragHorizontalDirection();
   3469 
   3470 		if ( this.floating && horizontalDirection ) {
   3471 			return ( ( horizontalDirection === "right" && isOverRightHalf ) ||
   3472 				( horizontalDirection === "left" && !isOverRightHalf ) );
   3473 		} else {
   3474 			return verticalDirection && ( ( verticalDirection === "down" && isOverBottomHalf ) ||
   3475 				( verticalDirection === "up" && !isOverBottomHalf ) );
   3476 		}
   3477 
   3478 	},
   3479 
   3480 	_getDragVerticalDirection: function() {
   3481 		var delta = this.positionAbs.top - this.lastPositionAbs.top;
   3482 		return delta !== 0 && ( delta > 0 ? "down" : "up" );
   3483 	},
   3484 
   3485 	_getDragHorizontalDirection: function() {
   3486 		var delta = this.positionAbs.left - this.lastPositionAbs.left;
   3487 		return delta !== 0 && ( delta > 0 ? "right" : "left" );
   3488 	},
   3489 
   3490 	refresh: function( event ) {
   3491 		this._refreshItems( event );
   3492 		this._setHandleClassName();
   3493 		this.refreshPositions();
   3494 		return this;
   3495 	},
   3496 
   3497 	_connectWith: function() {
   3498 		var options = this.options;
   3499 		return options.connectWith.constructor === String ?
   3500 			[ options.connectWith ] :
   3501 			options.connectWith;
   3502 	},
   3503 
   3504 	_getItemsAsjQuery: function( connected ) {
   3505 
   3506 		var i, j, cur, inst,
   3507 			items = [],
   3508 			queries = [],
   3509 			connectWith = this._connectWith();
   3510 
   3511 		if ( connectWith && connected ) {
   3512 			for ( i = connectWith.length - 1; i >= 0; i-- ) {
   3513 				cur = $( connectWith[ i ], this.document[ 0 ] );
   3514 				for ( j = cur.length - 1; j >= 0; j-- ) {
   3515 					inst = $.data( cur[ j ], this.widgetFullName );
   3516 					if ( inst && inst !== this && !inst.options.disabled ) {
   3517 						queries.push( [ $.isFunction( inst.options.items ) ?
   3518 							inst.options.items.call( inst.element ) :
   3519 							$( inst.options.items, inst.element )
   3520 								.not( ".ui-sortable-helper" )
   3521 								.not( ".ui-sortable-placeholder" ), inst ] );
   3522 					}
   3523 				}
   3524 			}
   3525 		}
   3526 
   3527 		queries.push( [ $.isFunction( this.options.items ) ?
   3528 			this.options.items
   3529 				.call( this.element, null, { options: this.options, item: this.currentItem } ) :
   3530 			$( this.options.items, this.element )
   3531 				.not( ".ui-sortable-helper" )
   3532 				.not( ".ui-sortable-placeholder" ), this ] );
   3533 
   3534 		function addItems() {
   3535 			items.push( this );
   3536 		}
   3537 		for ( i = queries.length - 1; i >= 0; i-- ) {
   3538 			queries[ i ][ 0 ].each( addItems );
   3539 		}
   3540 
   3541 		return $( items );
   3542 
   3543 	},
   3544 
   3545 	_removeCurrentsFromItems: function() {
   3546 
   3547 		var list = this.currentItem.find( ":data(" + this.widgetName + "-item)" );
   3548 
   3549 		this.items = $.grep( this.items, function( item ) {
   3550 			for ( var j = 0; j < list.length; j++ ) {
   3551 				if ( list[ j ] === item.item[ 0 ] ) {
   3552 					return false;
   3553 				}
   3554 			}
   3555 			return true;
   3556 		} );
   3557 
   3558 	},
   3559 
   3560 	_refreshItems: function( event ) {
   3561 
   3562 		this.items = [];
   3563 		this.containers = [ this ];
   3564 
   3565 		var i, j, cur, inst, targetData, _queries, item, queriesLength,
   3566 			items = this.items,
   3567 			queries = [ [ $.isFunction( this.options.items ) ?
   3568 				this.options.items.call( this.element[ 0 ], event, { item: this.currentItem } ) :
   3569 				$( this.options.items, this.element ), this ] ],
   3570 			connectWith = this._connectWith();
   3571 
   3572 		//Shouldn't be run the first time through due to massive slow-down
   3573 		if ( connectWith && this.ready ) {
   3574 			for ( i = connectWith.length - 1; i >= 0; i-- ) {
   3575 				cur = $( connectWith[ i ], this.document[ 0 ] );
   3576 				for ( j = cur.length - 1; j >= 0; j-- ) {
   3577 					inst = $.data( cur[ j ], this.widgetFullName );
   3578 					if ( inst && inst !== this && !inst.options.disabled ) {
   3579 						queries.push( [ $.isFunction( inst.options.items ) ?
   3580 							inst.options.items
   3581 								.call( inst.element[ 0 ], event, { item: this.currentItem } ) :
   3582 							$( inst.options.items, inst.element ), inst ] );
   3583 						this.containers.push( inst );
   3584 					}
   3585 				}
   3586 			}
   3587 		}
   3588 
   3589 		for ( i = queries.length - 1; i >= 0; i-- ) {
   3590 			targetData = queries[ i ][ 1 ];
   3591 			_queries = queries[ i ][ 0 ];
   3592 
   3593 			for ( j = 0, queriesLength = _queries.length; j < queriesLength; j++ ) {
   3594 				item = $( _queries[ j ] );
   3595 
   3596 				// Data for target checking (mouse manager)
   3597 				item.data( this.widgetName + "-item", targetData );
   3598 
   3599 				items.push( {
   3600 					item: item,
   3601 					instance: targetData,
   3602 					width: 0, height: 0,
   3603 					left: 0, top: 0
   3604 				} );
   3605 			}
   3606 		}
   3607 
   3608 	},
   3609 
   3610 	refreshPositions: function( fast ) {
   3611 
   3612 		// Determine whether items are being displayed horizontally
   3613 		this.floating = this.items.length ?
   3614 			this.options.axis === "x" || this._isFloating( this.items[ 0 ].item ) :
   3615 			false;
   3616 
   3617 		//This has to be redone because due to the item being moved out/into the offsetParent,
   3618 		// the offsetParent's position will change
   3619 		if ( this.offsetParent && this.helper ) {
   3620 			this.offset.parent = this._getParentOffset();
   3621 		}
   3622 
   3623 		var i, item, t, p;
   3624 
   3625 		for ( i = this.items.length - 1; i >= 0; i-- ) {
   3626 			item = this.items[ i ];
   3627 
   3628 			//We ignore calculating positions of all connected containers when we're not over them
   3629 			if ( item.instance !== this.currentContainer && this.currentContainer &&
   3630 					item.item[ 0 ] !== this.currentItem[ 0 ] ) {
   3631 				continue;
   3632 			}
   3633 
   3634 			t = this.options.toleranceElement ?
   3635 				$( this.options.toleranceElement, item.item ) :
   3636 				item.item;
   3637 
   3638 			if ( !fast ) {
   3639 				item.width = t.outerWidth();
   3640 				item.height = t.outerHeight();
   3641 			}
   3642 
   3643 			p = t.offset();
   3644 			item.left = p.left;
   3645 			item.top = p.top;
   3646 		}
   3647 
   3648 		if ( this.options.custom && this.options.custom.refreshContainers ) {
   3649 			this.options.custom.refreshContainers.call( this );
   3650 		} else {
   3651 			for ( i = this.containers.length - 1; i >= 0; i-- ) {
   3652 				p = this.containers[ i ].element.offset();
   3653 				this.containers[ i ].containerCache.left = p.left;
   3654 				this.containers[ i ].containerCache.top = p.top;
   3655 				this.containers[ i ].containerCache.width =
   3656 					this.containers[ i ].element.outerWidth();
   3657 				this.containers[ i ].containerCache.height =
   3658 					this.containers[ i ].element.outerHeight();
   3659 			}
   3660 		}
   3661 
   3662 		return this;
   3663 	},
   3664 
   3665 	_createPlaceholder: function( that ) {
   3666 		that = that || this;
   3667 		var className,
   3668 			o = that.options;
   3669 
   3670 		if ( !o.placeholder || o.placeholder.constructor === String ) {
   3671 			className = o.placeholder;
   3672 			o.placeholder = {
   3673 				element: function() {
   3674 
   3675 					var nodeName = that.currentItem[ 0 ].nodeName.toLowerCase(),
   3676 						element = $( "<" + nodeName + ">", that.document[ 0 ] );
   3677 
   3678 						that._addClass( element, "ui-sortable-placeholder",
   3679 								className || that.currentItem[ 0 ].className )
   3680 							._removeClass( element, "ui-sortable-helper" );
   3681 
   3682 					if ( nodeName === "tbody" ) {
   3683 						that._createTrPlaceholder(
   3684 							that.currentItem.find( "tr" ).eq( 0 ),
   3685 							$( "<tr>", that.document[ 0 ] ).appendTo( element )
   3686 						);
   3687 					} else if ( nodeName === "tr" ) {
   3688 						that._createTrPlaceholder( that.currentItem, element );
   3689 					} else if ( nodeName === "img" ) {
   3690 						element.attr( "src", that.currentItem.attr( "src" ) );
   3691 					}
   3692 
   3693 					if ( !className ) {
   3694 						element.css( "visibility", "hidden" );
   3695 					}
   3696 
   3697 					return element;
   3698 				},
   3699 				update: function( container, p ) {
   3700 
   3701 					// 1. If a className is set as 'placeholder option, we don't force sizes -
   3702 					// the class is responsible for that
   3703 					// 2. The option 'forcePlaceholderSize can be enabled to force it even if a
   3704 					// class name is specified
   3705 					if ( className && !o.forcePlaceholderSize ) {
   3706 						return;
   3707 					}
   3708 
   3709 					//If the element doesn't have a actual height by itself (without styles coming
   3710 					// from a stylesheet), it receives the inline height from the dragged item
   3711 					if ( !p.height() ) {
   3712 						p.height(
   3713 							that.currentItem.innerHeight() -
   3714 							parseInt( that.currentItem.css( "paddingTop" ) || 0, 10 ) -
   3715 							parseInt( that.currentItem.css( "paddingBottom" ) || 0, 10 ) );
   3716 					}
   3717 					if ( !p.width() ) {
   3718 						p.width(
   3719 							that.currentItem.innerWidth() -
   3720 							parseInt( that.currentItem.css( "paddingLeft" ) || 0, 10 ) -
   3721 							parseInt( that.currentItem.css( "paddingRight" ) || 0, 10 ) );
   3722 					}
   3723 				}
   3724 			};
   3725 		}
   3726 
   3727 		//Create the placeholder
   3728 		that.placeholder = $( o.placeholder.element.call( that.element, that.currentItem ) );
   3729 
   3730 		//Append it after the actual current item
   3731 		that.currentItem.after( that.placeholder );
   3732 
   3733 		//Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
   3734 		o.placeholder.update( that, that.placeholder );
   3735 
   3736 	},
   3737 
   3738 	_createTrPlaceholder: function( sourceTr, targetTr ) {
   3739 		var that = this;
   3740 
   3741 		sourceTr.children().each( function() {
   3742 			$( "<td>&#160;</td>", that.document[ 0 ] )
   3743 				.attr( "colspan", $( this ).attr( "colspan" ) || 1 )
   3744 				.appendTo( targetTr );
   3745 		} );
   3746 	},
   3747 
   3748 	_contactContainers: function( event ) {
   3749 		var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom,
   3750 			floating, axis,
   3751 			innermostContainer = null,
   3752 			innermostIndex = null;
   3753 
   3754 		// Get innermost container that intersects with item
   3755 		for ( i = this.containers.length - 1; i >= 0; i-- ) {
   3756 
   3757 			// Never consider a container that's located within the item itself
   3758 			if ( $.contains( this.currentItem[ 0 ], this.containers[ i ].element[ 0 ] ) ) {
   3759 				continue;
   3760 			}
   3761 
   3762 			if ( this._intersectsWith( this.containers[ i ].containerCache ) ) {
   3763 
   3764 				// If we've already found a container and it's more "inner" than this, then continue
   3765 				if ( innermostContainer &&
   3766 						$.contains(
   3767 							this.containers[ i ].element[ 0 ],
   3768 							innermostContainer.element[ 0 ] ) ) {
   3769 					continue;
   3770 				}
   3771 
   3772 				innermostContainer = this.containers[ i ];
   3773 				innermostIndex = i;
   3774 
   3775 			} else {
   3776 
   3777 				// container doesn't intersect. trigger "out" event if necessary
   3778 				if ( this.containers[ i ].containerCache.over ) {
   3779 					this.containers[ i ]._trigger( "out", event, this._uiHash( this ) );
   3780 					this.containers[ i ].containerCache.over = 0;
   3781 				}
   3782 			}
   3783 
   3784 		}
   3785 
   3786 		// If no intersecting containers found, return
   3787 		if ( !innermostContainer ) {
   3788 			return;
   3789 		}
   3790 
   3791 		// Move the item into the container if it's not there already
   3792 		if ( this.containers.length === 1 ) {
   3793 			if ( !this.containers[ innermostIndex ].containerCache.over ) {
   3794 				this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
   3795 				this.containers[ innermostIndex ].containerCache.over = 1;
   3796 			}
   3797 		} else {
   3798 
   3799 			// When entering a new container, we will find the item with the least distance and
   3800 			// append our item near it
   3801 			dist = 10000;
   3802 			itemWithLeastDistance = null;
   3803 			floating = innermostContainer.floating || this._isFloating( this.currentItem );
   3804 			posProperty = floating ? "left" : "top";
   3805 			sizeProperty = floating ? "width" : "height";
   3806 			axis = floating ? "pageX" : "pageY";
   3807 
   3808 			for ( j = this.items.length - 1; j >= 0; j-- ) {
   3809 				if ( !$.contains(
   3810 						this.containers[ innermostIndex ].element[ 0 ], this.items[ j ].item[ 0 ] )
   3811 				) {
   3812 					continue;
   3813 				}
   3814 				if ( this.items[ j ].item[ 0 ] === this.currentItem[ 0 ] ) {
   3815 					continue;
   3816 				}
   3817 
   3818 				cur = this.items[ j ].item.offset()[ posProperty ];
   3819 				nearBottom = false;
   3820 				if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) {
   3821 					nearBottom = true;
   3822 				}
   3823 
   3824 				if ( Math.abs( event[ axis ] - cur ) < dist ) {
   3825 					dist = Math.abs( event[ axis ] - cur );
   3826 					itemWithLeastDistance = this.items[ j ];
   3827 					this.direction = nearBottom ? "up" : "down";
   3828 				}
   3829 			}
   3830 
   3831 			//Check if dropOnEmpty is enabled
   3832 			if ( !itemWithLeastDistance && !this.options.dropOnEmpty ) {
   3833 				return;
   3834 			}
   3835 
   3836 			if ( this.currentContainer === this.containers[ innermostIndex ] ) {
   3837 				if ( !this.currentContainer.containerCache.over ) {
   3838 					this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() );
   3839 					this.currentContainer.containerCache.over = 1;
   3840 				}
   3841 				return;
   3842 			}
   3843 
   3844 			itemWithLeastDistance ?
   3845 				this._rearrange( event, itemWithLeastDistance, null, true ) :
   3846 				this._rearrange( event, null, this.containers[ innermostIndex ].element, true );
   3847 			this._trigger( "change", event, this._uiHash() );
   3848 			this.containers[ innermostIndex ]._trigger( "change", event, this._uiHash( this ) );
   3849 			this.currentContainer = this.containers[ innermostIndex ];
   3850 
   3851 			//Update the placeholder
   3852 			this.options.placeholder.update( this.currentContainer, this.placeholder );
   3853 
   3854 			this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
   3855 			this.containers[ innermostIndex ].containerCache.over = 1;
   3856 		}
   3857 
   3858 	},
   3859 
   3860 	_createHelper: function( event ) {
   3861 
   3862 		var o = this.options,
   3863 			helper = $.isFunction( o.helper ) ?
   3864 				$( o.helper.apply( this.element[ 0 ], [ event, this.currentItem ] ) ) :
   3865 				( o.helper === "clone" ? this.currentItem.clone() : this.currentItem );
   3866 
   3867 		//Add the helper to the DOM if that didn't happen already
   3868 		if ( !helper.parents( "body" ).length ) {
   3869 			$( o.appendTo !== "parent" ?
   3870 				o.appendTo :
   3871 				this.currentItem[ 0 ].parentNode )[ 0 ].appendChild( helper[ 0 ] );
   3872 		}
   3873 
   3874 		if ( helper[ 0 ] === this.currentItem[ 0 ] ) {
   3875 			this._storedCSS = {
   3876 				width: this.currentItem[ 0 ].style.width,
   3877 				height: this.currentItem[ 0 ].style.height,
   3878 				position: this.currentItem.css( "position" ),
   3879 				top: this.currentItem.css( "top" ),
   3880 				left: this.currentItem.css( "left" )
   3881 			};
   3882 		}
   3883 
   3884 		if ( !helper[ 0 ].style.width || o.forceHelperSize ) {
   3885 			helper.width( this.currentItem.width() );
   3886 		}
   3887 		if ( !helper[ 0 ].style.height || o.forceHelperSize ) {
   3888 			helper.height( this.currentItem.height() );
   3889 		}
   3890 
   3891 		return helper;
   3892 
   3893 	},
   3894 
   3895 	_adjustOffsetFromHelper: function( obj ) {
   3896 		if ( typeof obj === "string" ) {
   3897 			obj = obj.split( " " );
   3898 		}
   3899 		if ( $.isArray( obj ) ) {
   3900 			obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 };
   3901 		}
   3902 		if ( "left" in obj ) {
   3903 			this.offset.click.left = obj.left + this.margins.left;
   3904 		}
   3905 		if ( "right" in obj ) {
   3906 			this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
   3907 		}
   3908 		if ( "top" in obj ) {
   3909 			this.offset.click.top = obj.top + this.margins.top;
   3910 		}
   3911 		if ( "bottom" in obj ) {
   3912 			this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
   3913 		}
   3914 	},
   3915 
   3916 	_getParentOffset: function() {
   3917 
   3918 		//Get the offsetParent and cache its position
   3919 		this.offsetParent = this.helper.offsetParent();
   3920 		var po = this.offsetParent.offset();
   3921 
   3922 		// This is a special case where we need to modify a offset calculated on start, since the
   3923 		// following happened:
   3924 		// 1. The position of the helper is absolute, so it's position is calculated based on the
   3925 		// next positioned parent
   3926 		// 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't
   3927 		// the document, which means that the scroll is included in the initial calculation of the
   3928 		// offset of the parent, and never recalculated upon drag
   3929 		if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== this.document[ 0 ] &&
   3930 				$.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) {
   3931 			po.left += this.scrollParent.scrollLeft();
   3932 			po.top += this.scrollParent.scrollTop();
   3933 		}
   3934 
   3935 		// This needs to be actually done for all browsers, since pageX/pageY includes this
   3936 		// information with an ugly IE fix
   3937 		if ( this.offsetParent[ 0 ] === this.document[ 0 ].body ||
   3938 				( this.offsetParent[ 0 ].tagName &&
   3939 				this.offsetParent[ 0 ].tagName.toLowerCase() === "html" && $.ui.ie ) ) {
   3940 			po = { top: 0, left: 0 };
   3941 		}
   3942 
   3943 		return {
   3944 			top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ),
   3945 			left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 )
   3946 		};
   3947 
   3948 	},
   3949 
   3950 	_getRelativeOffset: function() {
   3951 
   3952 		if ( this.cssPosition === "relative" ) {
   3953 			var p = this.currentItem.position();
   3954 			return {
   3955 				top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) +
   3956 					this.scrollParent.scrollTop(),
   3957 				left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) +
   3958 					this.scrollParent.scrollLeft()
   3959 			};
   3960 		} else {
   3961 			return { top: 0, left: 0 };
   3962 		}
   3963 
   3964 	},
   3965 
   3966 	_cacheMargins: function() {
   3967 		this.margins = {
   3968 			left: ( parseInt( this.currentItem.css( "marginLeft" ), 10 ) || 0 ),
   3969 			top: ( parseInt( this.currentItem.css( "marginTop" ), 10 ) || 0 )
   3970 		};
   3971 	},
   3972 
   3973 	_cacheHelperProportions: function() {
   3974 		this.helperProportions = {
   3975 			width: this.helper.outerWidth(),
   3976 			height: this.helper.outerHeight()
   3977 		};
   3978 	},
   3979 
   3980 	_setContainment: function() {
   3981 
   3982 		var ce, co, over,
   3983 			o = this.options;
   3984 		if ( o.containment === "parent" ) {
   3985 			o.containment = this.helper[ 0 ].parentNode;
   3986 		}
   3987 		if ( o.containment === "document" || o.containment === "window" ) {
   3988 			this.containment = [
   3989 				0 - this.offset.relative.left - this.offset.parent.left,
   3990 				0 - this.offset.relative.top - this.offset.parent.top,
   3991 				o.containment === "document" ?
   3992 					this.document.width() :
   3993 					this.window.width() - this.helperProportions.width - this.margins.left,
   3994 				( o.containment === "document" ?
   3995 					( this.document.height() || document.body.parentNode.scrollHeight ) :
   3996 					this.window.height() || this.document[ 0 ].body.parentNode.scrollHeight
   3997 				) - this.helperProportions.height - this.margins.top
   3998 			];
   3999 		}
   4000 
   4001 		if ( !( /^(document|window|parent)$/ ).test( o.containment ) ) {
   4002 			ce = $( o.containment )[ 0 ];
   4003 			co = $( o.containment ).offset();
   4004 			over = ( $( ce ).css( "overflow" ) !== "hidden" );
   4005 
   4006 			this.containment = [
   4007 				co.left + ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) +
   4008 					( parseInt( $( ce ).css( "paddingLeft" ), 10 ) || 0 ) - this.margins.left,
   4009 				co.top + ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) +
   4010 					( parseInt( $( ce ).css( "paddingTop" ), 10 ) || 0 ) - this.margins.top,
   4011 				co.left + ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
   4012 					( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) -
   4013 					( parseInt( $( ce ).css( "paddingRight" ), 10 ) || 0 ) -
   4014 					this.helperProportions.width - this.margins.left,
   4015 				co.top + ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
   4016 					( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) -
   4017 					( parseInt( $( ce ).css( "paddingBottom" ), 10 ) || 0 ) -
   4018 					this.helperProportions.height - this.margins.top
   4019 			];
   4020 		}
   4021 
   4022 	},
   4023 
   4024 	_convertPositionTo: function( d, pos ) {
   4025 
   4026 		if ( !pos ) {
   4027 			pos = this.position;
   4028 		}
   4029 		var mod = d === "absolute" ? 1 : -1,
   4030 			scroll = this.cssPosition === "absolute" &&
   4031 				!( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
   4032 				$.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
   4033 					this.offsetParent :
   4034 					this.scrollParent,
   4035 			scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );
   4036 
   4037 		return {
   4038 			top: (
   4039 
   4040 				// The absolute mouse position
   4041 				pos.top	+
   4042 
   4043 				// Only for relative positioned nodes: Relative offset from element to offset parent
   4044 				this.offset.relative.top * mod +
   4045 
   4046 				// The offsetParent's offset without borders (offset + border)
   4047 				this.offset.parent.top * mod -
   4048 				( ( this.cssPosition === "fixed" ?
   4049 					-this.scrollParent.scrollTop() :
   4050 					( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod )
   4051 			),
   4052 			left: (
   4053 
   4054 				// The absolute mouse position
   4055 				pos.left +
   4056 
   4057 				// Only for relative positioned nodes: Relative offset from element to offset parent
   4058 				this.offset.relative.left * mod +
   4059 
   4060 				// The offsetParent's offset without borders (offset + border)
   4061 				this.offset.parent.left * mod	-
   4062 				( ( this.cssPosition === "fixed" ?
   4063 					-this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 :
   4064 					scroll.scrollLeft() ) * mod )
   4065 			)
   4066 		};
   4067 
   4068 	},
   4069 
   4070 	_generatePosition: function( event ) {
   4071 
   4072 		var top, left,
   4073 			o = this.options,
   4074 			pageX = event.pageX,
   4075 			pageY = event.pageY,
   4076 			scroll = this.cssPosition === "absolute" &&
   4077 				!( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
   4078 				$.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
   4079 					this.offsetParent :
   4080 					this.scrollParent,
   4081 				scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );
   4082 
   4083 		// This is another very weird special case that only happens for relative elements:
   4084 		// 1. If the css position is relative
   4085 		// 2. and the scroll parent is the document or similar to the offset parent
   4086 		// we have to refresh the relative offset during the scroll so there are no jumps
   4087 		if ( this.cssPosition === "relative" && !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
   4088 				this.scrollParent[ 0 ] !== this.offsetParent[ 0 ] ) ) {
   4089 			this.offset.relative = this._getRelativeOffset();
   4090 		}
   4091 
   4092 		/*
   4093 		 * - Position constraining -
   4094 		 * Constrain the position to a mix of grid, containment.
   4095 		 */
   4096 
   4097 		if ( this.originalPosition ) { //If we are not dragging yet, we won't check for options
   4098 
   4099 			if ( this.containment ) {
   4100 				if ( event.pageX - this.offset.click.left < this.containment[ 0 ] ) {
   4101 					pageX = this.containment[ 0 ] + this.offset.click.left;
   4102 				}
   4103 				if ( event.pageY - this.offset.click.top < this.containment[ 1 ] ) {
   4104 					pageY = this.containment[ 1 ] + this.offset.click.top;
   4105 				}
   4106 				if ( event.pageX - this.offset.click.left > this.containment[ 2 ] ) {
   4107 					pageX = this.containment[ 2 ] + this.offset.click.left;
   4108 				}
   4109 				if ( event.pageY - this.offset.click.top > this.containment[ 3 ] ) {
   4110 					pageY = this.containment[ 3 ] + this.offset.click.top;
   4111 				}
   4112 			}
   4113 
   4114 			if ( o.grid ) {
   4115 				top = this.originalPageY + Math.round( ( pageY - this.originalPageY ) /
   4116 					o.grid[ 1 ] ) * o.grid[ 1 ];
   4117 				pageY = this.containment ?
   4118 					( ( top - this.offset.click.top >= this.containment[ 1 ] &&
   4119 						top - this.offset.click.top <= this.containment[ 3 ] ) ?
   4120 							top :
   4121 							( ( top - this.offset.click.top >= this.containment[ 1 ] ) ?
   4122 								top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) :
   4123 								top;
   4124 
   4125 				left = this.originalPageX + Math.round( ( pageX - this.originalPageX ) /
   4126 					o.grid[ 0 ] ) * o.grid[ 0 ];
   4127 				pageX = this.containment ?
   4128 					( ( left - this.offset.click.left >= this.containment[ 0 ] &&
   4129 						left - this.offset.click.left <= this.containment[ 2 ] ) ?
   4130 							left :
   4131 							( ( left - this.offset.click.left >= this.containment[ 0 ] ) ?
   4132 								left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) :
   4133 								left;
   4134 			}
   4135 
   4136 		}
   4137 
   4138 		return {
   4139 			top: (
   4140 
   4141 				// The absolute mouse position
   4142 				pageY -
   4143 
   4144 				// Click offset (relative to the element)
   4145 				this.offset.click.top -
   4146 
   4147 				// Only for relative positioned nodes: Relative offset from element to offset parent
   4148 				this.offset.relative.top -
   4149 
   4150 				// The offsetParent's offset without borders (offset + border)
   4151 				this.offset.parent.top +
   4152 				( ( this.cssPosition === "fixed" ?
   4153 					-this.scrollParent.scrollTop() :
   4154 					( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) )
   4155 			),
   4156 			left: (
   4157 
   4158 				// The absolute mouse position
   4159 				pageX -
   4160 
   4161 				// Click offset (relative to the element)
   4162 				this.offset.click.left -
   4163 
   4164 				// Only for relative positioned nodes: Relative offset from element to offset parent
   4165 				this.offset.relative.left -
   4166 
   4167 				// The offsetParent's offset without borders (offset + border)
   4168 				this.offset.parent.left +
   4169 				( ( this.cssPosition === "fixed" ?
   4170 					-this.scrollParent.scrollLeft() :
   4171 					scrollIsRootNode ? 0 : scroll.scrollLeft() ) )
   4172 			)
   4173 		};
   4174 
   4175 	},
   4176 
   4177 	_rearrange: function( event, i, a, hardRefresh ) {
   4178 
   4179 		a ? a[ 0 ].appendChild( this.placeholder[ 0 ] ) :
   4180 			i.item[ 0 ].parentNode.insertBefore( this.placeholder[ 0 ],
   4181 				( this.direction === "down" ? i.item[ 0 ] : i.item[ 0 ].nextSibling ) );
   4182 
   4183 		//Various things done here to improve the performance:
   4184 		// 1. we create a setTimeout, that calls refreshPositions
   4185 		// 2. on the instance, we have a counter variable, that get's higher after every append
   4186 		// 3. on the local scope, we copy the counter variable, and check in the timeout,
   4187 		// if it's still the same
   4188 		// 4. this lets only the last addition to the timeout stack through
   4189 		this.counter = this.counter ? ++this.counter : 1;
   4190 		var counter = this.counter;
   4191 
   4192 		this._delay( function() {
   4193 			if ( counter === this.counter ) {
   4194 
   4195 				//Precompute after each DOM insertion, NOT on mousemove
   4196 				this.refreshPositions( !hardRefresh );
   4197 			}
   4198 		} );
   4199 
   4200 	},
   4201 
   4202 	_clear: function( event, noPropagation ) {
   4203 
   4204 		this.reverting = false;
   4205 
   4206 		// We delay all events that have to be triggered to after the point where the placeholder
   4207 		// has been removed and everything else normalized again
   4208 		var i,
   4209 			delayedTriggers = [];
   4210 
   4211 		// We first have to update the dom position of the actual currentItem
   4212 		// Note: don't do it if the current item is already removed (by a user), or it gets
   4213 		// reappended (see #4088)
   4214 		if ( !this._noFinalSort && this.currentItem.parent().length ) {
   4215 			this.placeholder.before( this.currentItem );
   4216 		}
   4217 		this._noFinalSort = null;
   4218 
   4219 		if ( this.helper[ 0 ] === this.currentItem[ 0 ] ) {
   4220 			for ( i in this._storedCSS ) {
   4221 				if ( this._storedCSS[ i ] === "auto" || this._storedCSS[ i ] === "static" ) {
   4222 					this._storedCSS[ i ] = "";
   4223 				}
   4224 			}
   4225 			this.currentItem.css( this._storedCSS );
   4226 			this._removeClass( this.currentItem, "ui-sortable-helper" );
   4227 		} else {
   4228 			this.currentItem.show();
   4229 		}
   4230 
   4231 		if ( this.fromOutside && !noPropagation ) {
   4232 			delayedTriggers.push( function( event ) {
   4233 				this._trigger( "receive", event, this._uiHash( this.fromOutside ) );
   4234 			} );
   4235 		}
   4236 		if ( ( this.fromOutside ||
   4237 				this.domPosition.prev !==
   4238 				this.currentItem.prev().not( ".ui-sortable-helper" )[ 0 ] ||
   4239 				this.domPosition.parent !== this.currentItem.parent()[ 0 ] ) && !noPropagation ) {
   4240 
   4241 			// Trigger update callback if the DOM position has changed
   4242 			delayedTriggers.push( function( event ) {
   4243 				this._trigger( "update", event, this._uiHash() );
   4244 			} );
   4245 		}
   4246 
   4247 		// Check if the items Container has Changed and trigger appropriate
   4248 		// events.
   4249 		if ( this !== this.currentContainer ) {
   4250 			if ( !noPropagation ) {
   4251 				delayedTriggers.push( function( event ) {
   4252 					this._trigger( "remove", event, this._uiHash() );
   4253 				} );
   4254 				delayedTriggers.push( ( function( c ) {
   4255 					return function( event ) {
   4256 						c._trigger( "receive", event, this._uiHash( this ) );
   4257 					};
   4258 				} ).call( this, this.currentContainer ) );
   4259 				delayedTriggers.push( ( function( c ) {
   4260 					return function( event ) {
   4261 						c._trigger( "update", event, this._uiHash( this ) );
   4262 					};
   4263 				} ).call( this, this.currentContainer ) );
   4264 			}
   4265 		}
   4266 
   4267 		//Post events to containers
   4268 		function delayEvent( type, instance, container ) {
   4269 			return function( event ) {
   4270 				container._trigger( type, event, instance._uiHash( instance ) );
   4271 			};
   4272 		}
   4273 		for ( i = this.containers.length - 1; i >= 0; i-- ) {
   4274 			if ( !noPropagation ) {
   4275 				delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) );
   4276 			}
   4277 			if ( this.containers[ i ].containerCache.over ) {
   4278 				delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) );
   4279 				this.containers[ i ].containerCache.over = 0;
   4280 			}
   4281 		}
   4282 
   4283 		//Do what was originally in plugins
   4284 		if ( this.storedCursor ) {
   4285 			this.document.find( "body" ).css( "cursor", this.storedCursor );
   4286 			this.storedStylesheet.remove();
   4287 		}
   4288 		if ( this._storedOpacity ) {
   4289 			this.helper.css( "opacity", this._storedOpacity );
   4290 		}
   4291 		if ( this._storedZIndex ) {
   4292 			this.helper.css( "zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex );
   4293 		}
   4294 
   4295 		this.dragging = false;
   4296 
   4297 		if ( !noPropagation ) {
   4298 			this._trigger( "beforeStop", event, this._uiHash() );
   4299 		}
   4300 
   4301 		//$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
   4302 		// it unbinds ALL events from the original node!
   4303 		this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );
   4304 
   4305 		if ( !this.cancelHelperRemoval ) {
   4306 			if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
   4307 				this.helper.remove();
   4308 			}
   4309 			this.helper = null;
   4310 		}
   4311 
   4312 		if ( !noPropagation ) {
   4313 			for ( i = 0; i < delayedTriggers.length; i++ ) {
   4314 
   4315 				// Trigger all delayed events
   4316 				delayedTriggers[ i ].call( this, event );
   4317 			}
   4318 			this._trigger( "stop", event, this._uiHash() );
   4319 		}
   4320 
   4321 		this.fromOutside = false;
   4322 		return !this.cancelHelperRemoval;
   4323 
   4324 	},
   4325 
   4326 	_trigger: function() {
   4327 		if ( $.Widget.prototype._trigger.apply( this, arguments ) === false ) {
   4328 			this.cancel();
   4329 		}
   4330 	},
   4331 
   4332 	_uiHash: function( _inst ) {
   4333 		var inst = _inst || this;
   4334 		return {
   4335 			helper: inst.helper,
   4336 			placeholder: inst.placeholder || $( [] ),
   4337 			position: inst.position,
   4338 			originalPosition: inst.originalPosition,
   4339 			offset: inst.positionAbs,
   4340 			item: inst.currentItem,
   4341 			sender: _inst ? _inst.element : null
   4342 		};
   4343 	}
   4344 
   4345 } );
   4346 
   4347 
   4348 
   4349 
   4350 }));