app/jquery/jquery-ui.draggable.js
changeset 2749 4e2789b8e86d
parent 2420 645f4de26f99
equal deleted inserted replaced
2748:7fbc98f3adde 2749:4e2789b8e86d
     1 /*
     1 /*
     2  * jQuery UI Draggable 1.6
     2  * jQuery UI Draggable 1.7.2
     3  *
     3  *
     4  * Copyright (c) 2008 AUTHORS.txt (http://ui.jquery.com/about)
     4  * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
     5  * Dual licensed under the MIT (MIT-LICENSE.txt)
     5  * Dual licensed under the MIT (MIT-LICENSE.txt)
     6  * and GPL (GPL-LICENSE.txt) licenses.
     6  * and GPL (GPL-LICENSE.txt) licenses.
     7  *
     7  *
     8  * http://docs.jquery.com/UI/Draggables
     8  * http://docs.jquery.com/UI/Draggables
     9  *
     9  *
    17 	_init: function() {
    17 	_init: function() {
    18 
    18 
    19 		if (this.options.helper == 'original' && !(/^(?:r|a|f)/).test(this.element.css("position")))
    19 		if (this.options.helper == 'original' && !(/^(?:r|a|f)/).test(this.element.css("position")))
    20 			this.element[0].style.position = 'relative';
    20 			this.element[0].style.position = 'relative';
    21 
    21 
    22 		(this.options.cssNamespace && this.element.addClass(this.options.cssNamespace+"-draggable"));
    22 		(this.options.addClasses && this.element.addClass("ui-draggable"));
    23 		(this.options.disabled && this.element.addClass('ui-draggable-disabled'));
    23 		(this.options.disabled && this.element.addClass("ui-draggable-disabled"));
    24 
    24 
    25 		this._mouseInit();
    25 		this._mouseInit();
    26 
    26 
    27 	},
    27 	},
    28 
    28 
    29 	destroy: function() {
    29 	destroy: function() {
    30 		if(!this.element.data('draggable')) return;
    30 		if(!this.element.data('draggable')) return;
    31 		this.element.removeData("draggable").unbind(".draggable").removeClass('ui-draggable ui-draggable-dragging ui-draggable-disabled');
    31 		this.element
       
    32 			.removeData("draggable")
       
    33 			.unbind(".draggable")
       
    34 			.removeClass("ui-draggable"
       
    35 				+ " ui-draggable-dragging"
       
    36 				+ " ui-draggable-disabled");
    32 		this._mouseDestroy();
    37 		this._mouseDestroy();
    33 	},
    38 	},
    34 
    39 
    35 	_mouseCapture: function(event) {
    40 	_mouseCapture: function(event) {
    36 
    41 
    88 			},
    93 			},
    89 			parent: this._getParentOffset(),
    94 			parent: this._getParentOffset(),
    90 			relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
    95 			relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
    91 		});
    96 		});
    92 
    97 
       
    98 		//Generate the original position
       
    99 		this.originalPosition = this._generatePosition(event);
       
   100 		this.originalPageX = event.pageX;
       
   101 		this.originalPageY = event.pageY;
       
   102 
    93 		//Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
   103 		//Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
    94 		if(o.cursorAt)
   104 		if(o.cursorAt)
    95 			this._adjustOffsetFromHelper(o.cursorAt);
   105 			this._adjustOffsetFromHelper(o.cursorAt);
    96 
   106 
    97 		//Generate the original position
       
    98 		this.originalPosition = this._generatePosition(event);
       
    99 
       
   100 		//Set a containment if given in the options
   107 		//Set a containment if given in the options
   101 		if(o.containment)
   108 		if(o.containment)
   102 			this._setContainment();
   109 			this._setContainment();
   103 
   110 
   104 		//Call plugins and callbacks
   111 		//Call plugins and callbacks
   105 		this._propagate("start", event);
   112 		this._trigger("start", event);
   106 
   113 
   107 		//Recache the helper size
   114 		//Recache the helper size
   108 		this._cacheHelperProportions();
   115 		this._cacheHelperProportions();
   109 
   116 
   110 		//Prepare the droppable offsets
   117 		//Prepare the droppable offsets
   121 		//Compute the helpers position
   128 		//Compute the helpers position
   122 		this.position = this._generatePosition(event);
   129 		this.position = this._generatePosition(event);
   123 		this.positionAbs = this._convertPositionTo("absolute");
   130 		this.positionAbs = this._convertPositionTo("absolute");
   124 
   131 
   125 		//Call plugins and callbacks and use the resulting position if something is returned
   132 		//Call plugins and callbacks and use the resulting position if something is returned
   126 		if(!noPropagation) this.position = this._propagate("drag", event) || this.position;
   133 		if (!noPropagation) {
       
   134 			var ui = this._uiHash();
       
   135 			this._trigger('drag', event, ui);
       
   136 			this.position = ui.position;
       
   137 		}
   127 
   138 
   128 		if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
   139 		if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
   129 		if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
   140 		if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
   130 		if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
   141 		if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
   131 
   142 
   135 	_mouseStop: function(event) {
   146 	_mouseStop: function(event) {
   136 
   147 
   137 		//If we are using droppables, inform the manager about the drop
   148 		//If we are using droppables, inform the manager about the drop
   138 		var dropped = false;
   149 		var dropped = false;
   139 		if ($.ui.ddmanager && !this.options.dropBehaviour)
   150 		if ($.ui.ddmanager && !this.options.dropBehaviour)
   140 			var dropped = $.ui.ddmanager.drop(this, event);
   151 			dropped = $.ui.ddmanager.drop(this, event);
       
   152 
       
   153 		//if a drop comes from outside (a sortable)
       
   154 		if(this.dropped) {
       
   155 			dropped = this.dropped;
       
   156 			this.dropped = false;
       
   157 		}
   141 
   158 
   142 		if((this.options.revert == "invalid" && !dropped) || (this.options.revert == "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) {
   159 		if((this.options.revert == "invalid" && !dropped) || (this.options.revert == "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) {
   143 			var self = this;
   160 			var self = this;
   144 			$(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
   161 			$(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
   145 				self._propagate("stop", event);
   162 				self._trigger("stop", event);
   146 				self._clear();
   163 				self._clear();
   147 			});
   164 			});
   148 		} else {
   165 		} else {
   149 			this._propagate("stop", event);
   166 			this._trigger("stop", event);
   150 			this._clear();
   167 			this._clear();
   151 		}
   168 		}
   152 
   169 
   153 		return false;
   170 		return false;
   154 	},
   171 	},
   189 		if(obj.bottom != undefined) this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
   206 		if(obj.bottom != undefined) this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
   190 	},
   207 	},
   191 
   208 
   192 	_getParentOffset: function() {
   209 	_getParentOffset: function() {
   193 
   210 
   194 		this.offsetParent = this.helper.offsetParent(); var po = this.offsetParent.offset();			//Get the offsetParent and cache its position
   211 		//Get the offsetParent and cache its position
   195 
   212 		this.offsetParent = this.helper.offsetParent();
   196 		if((this.offsetParent[0] == document.body && $.browser.mozilla)	//Ugly FF3 fix
   213 		var po = this.offsetParent.offset();
       
   214 
       
   215 		// This is a special case where we need to modify a offset calculated on start, since the following happened:
       
   216 		// 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
       
   217 		// 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
       
   218 		//    the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
       
   219 		if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) {
       
   220 			po.left += this.scrollParent.scrollLeft();
       
   221 			po.top += this.scrollParent.scrollTop();
       
   222 		}
       
   223 
       
   224 		if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information
   197 		|| (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix
   225 		|| (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix
   198 			po = { top: 0, left: 0 };
   226 			po = { top: 0, left: 0 };
   199 
   227 
   200 		return {
   228 		return {
   201 			top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
   229 			top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
   237 		var o = this.options;
   265 		var o = this.options;
   238 		if(o.containment == 'parent') o.containment = this.helper[0].parentNode;
   266 		if(o.containment == 'parent') o.containment = this.helper[0].parentNode;
   239 		if(o.containment == 'document' || o.containment == 'window') this.containment = [
   267 		if(o.containment == 'document' || o.containment == 'window') this.containment = [
   240 			0 - this.offset.relative.left - this.offset.parent.left,
   268 			0 - this.offset.relative.left - this.offset.parent.left,
   241 			0 - this.offset.relative.top - this.offset.parent.top,
   269 			0 - this.offset.relative.top - this.offset.parent.top,
   242 			$(o.containment == 'document' ? document : window).width() - this.offset.relative.left - this.offset.parent.left - this.helperProportions.width - this.margins.left - (parseInt(this.element.css("marginRight"),10) || 0),
   270 			$(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left,
   243 			($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.offset.relative.top - this.offset.parent.top - this.helperProportions.height - this.margins.top - (parseInt(this.element.css("marginBottom"),10) || 0)
   271 			($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
   244 		];
   272 		];
   245 
   273 
   246 		if(!(/^(document|window|parent)$/).test(o.containment)) {
   274 		if(!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor != Array) {
   247 			var ce = $(o.containment)[0];
   275 			var ce = $(o.containment)[0]; if(!ce) return;
   248 			var co = $(o.containment).offset();
   276 			var co = $(o.containment).offset();
   249 			var over = ($(ce).css("overflow") != 'hidden');
   277 			var over = ($(ce).css("overflow") != 'hidden');
   250 
   278 
   251 			this.containment = [
   279 			this.containment = [
   252 				co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) - this.offset.relative.left - this.offset.parent.left - this.margins.left,
   280 				co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
   253 				co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) - this.offset.relative.top - this.offset.parent.top - this.margins.top,
   281 				co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
   254 				co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - this.offset.relative.left - this.offset.parent.left - this.helperProportions.width - this.margins.left,
   282 				co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left,
   255 				co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - this.offset.relative.top - this.offset.parent.top - this.helperProportions.height - this.margins.top
   283 				co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top
   256 			];
   284 			];
       
   285 		} else if(o.containment.constructor == Array) {
       
   286 			this.containment = o.containment;
   257 		}
   287 		}
   258 
   288 
   259 	},
   289 	},
   260 
   290 
   261 	_convertPositionTo: function(d, pos) {
   291 	_convertPositionTo: function(d, pos) {
   262 
   292 
   263 		if(!pos) pos = this.position;
   293 		if(!pos) pos = this.position;
   264 		var mod = d == "absolute" ? 1 : -1;
   294 		var mod = d == "absolute" ? 1 : -1;
   265 		var scroll = this[(this.cssPosition == 'absolute' ? 'offset' : 'scroll')+'Parent'], scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
   295 		var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
   266 
   296 
   267 		return {
   297 		return {
   268 			top: (
   298 			top: (
   269 				pos.top																	// the calculated relative position
   299 				pos.top																	// The absolute mouse position
   270 				+ this.offset.relative.top	* mod										// Only for relative positioned nodes: Relative offset from element to offset parent
   300 				+ this.offset.relative.top * mod										// Only for relative positioned nodes: Relative offset from element to offset parent
   271 				+ this.offset.parent.top * mod											// The offsetParent's offset without borders (offset + border)
   301 				+ this.offset.parent.top * mod											// The offsetParent's offset without borders (offset + border)
   272 				+ ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod
   302 				- ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
   273 				+ this.margins.top * mod												//Add the margin (you don't want the margin counting in intersection methods)
       
   274 			),
   303 			),
   275 			left: (
   304 			left: (
   276 				pos.left																// the calculated relative position
   305 				pos.left																// The absolute mouse position
   277 				+ this.offset.relative.left	* mod										// Only for relative positioned nodes: Relative offset from element to offset parent
   306 				+ this.offset.relative.left * mod										// Only for relative positioned nodes: Relative offset from element to offset parent
   278 				+ this.offset.parent.left * mod											// The offsetParent's offset without borders (offset + border)
   307 				+ this.offset.parent.left * mod											// The offsetParent's offset without borders (offset + border)
   279 				+ ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : ( scrollIsRootNode ? 0 : scroll.scrollLeft() ) ) * mod
   308 				- ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
   280 				+ this.margins.left * mod												//Add the margin (you don't want the margin counting in intersection methods)
       
   281 			)
   309 			)
   282 		};
   310 		};
       
   311 
   283 	},
   312 	},
   284 
   313 
   285 	_generatePosition: function(event) {
   314 	_generatePosition: function(event) {
   286 
   315 
   287 		var o = this.options, scroll = this[(this.cssPosition == 'absolute' ? 'offset' : 'scroll')+'Parent'], scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
   316 		var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
   288 
   317 
   289 		var position = {
   318 		// This is another very weird special case that only happens for relative elements:
   290 			top: (
   319 		// 1. If the css position is relative
   291 				event.pageY																// The absolute mouse position
   320 		// 2. and the scroll parent is the document or similar to the offset parent
   292 				- this.offset.click.top													// Click offset (relative to the element)
   321 		// we have to refresh the relative offset during the scroll so there are no jumps
   293 				- this.offset.relative.top												// Only for relative positioned nodes: Relative offset from element to offset parent
   322 		if(this.cssPosition == 'relative' && !(this.scrollParent[0] != document && this.scrollParent[0] != this.offsetParent[0])) {
   294 				- this.offset.parent.top												// The offsetParent's offset without borders (offset + border)
   323 			this.offset.relative = this._getRelativeOffset();
   295 				+ ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )
   324 		}
   296 			),
   325 
   297 			left: (
   326 		var pageX = event.pageX;
   298 				event.pageX																// The absolute mouse position
   327 		var pageY = event.pageY;
   299 				- this.offset.click.left												// Click offset (relative to the element)
       
   300 				- this.offset.relative.left												// Only for relative positioned nodes: Relative offset from element to offset parent
       
   301 				- this.offset.parent.left												// The offsetParent's offset without borders (offset + border)
       
   302 				+ ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )
       
   303 			)
       
   304 		};
       
   305 
       
   306 		if(!this.originalPosition) return position;										//If we are not dragging yet, we won't check for options
       
   307 
   328 
   308 		/*
   329 		/*
   309 		 * - Position constraining -
   330 		 * - Position constraining -
   310 		 * Constrain the position to a mix of grid, containment.
   331 		 * Constrain the position to a mix of grid, containment.
   311 		 */
   332 		 */
   312 		if(this.containment) {
   333 
   313 			if(position.left < this.containment[0]) position.left = this.containment[0];
   334 		if(this.originalPosition) { //If we are not dragging yet, we won't check for options
   314 			if(position.top < this.containment[1]) position.top = this.containment[1];
   335 
   315 			if(position.left > this.containment[2]) position.left = this.containment[2];
   336 			if(this.containment) {
   316 			if(position.top > this.containment[3]) position.top = this.containment[3];
   337 				if(event.pageX - this.offset.click.left < this.containment[0]) pageX = this.containment[0] + this.offset.click.left;
   317 		}
   338 				if(event.pageY - this.offset.click.top < this.containment[1]) pageY = this.containment[1] + this.offset.click.top;
   318 
   339 				if(event.pageX - this.offset.click.left > this.containment[2]) pageX = this.containment[2] + this.offset.click.left;
   319 		if(o.grid) {
   340 				if(event.pageY - this.offset.click.top > this.containment[3]) pageY = this.containment[3] + this.offset.click.top;
   320 			var top = this.originalPosition.top + Math.round((position.top - this.originalPosition.top) / o.grid[1]) * o.grid[1];
   341 			}
   321 			position.top = this.containment ? (!(top < this.containment[1] || top > this.containment[3]) ? top : (!(top < this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
   342 
   322 
   343 			if(o.grid) {
   323 			var left = this.originalPosition.left + Math.round((position.left - this.originalPosition.left) / o.grid[0]) * o.grid[0];
   344 				var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
   324 			position.left = this.containment ? (!(left < this.containment[0] || left > this.containment[2]) ? left : (!(left < this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
   345 				pageY = this.containment ? (!(top - this.offset.click.top < this.containment[1] || top - this.offset.click.top > this.containment[3]) ? top : (!(top - this.offset.click.top < this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
   325 		}
   346 
   326 
   347 				var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
   327 		return position;
   348 				pageX = this.containment ? (!(left - this.offset.click.left < this.containment[0] || left - this.offset.click.left > this.containment[2]) ? left : (!(left - this.offset.click.left < this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
       
   349 			}
       
   350 
       
   351 		}
       
   352 
       
   353 		return {
       
   354 			top: (
       
   355 				pageY																// The absolute mouse position
       
   356 				- this.offset.click.top													// Click offset (relative to the element)
       
   357 				- this.offset.relative.top												// Only for relative positioned nodes: Relative offset from element to offset parent
       
   358 				- this.offset.parent.top												// The offsetParent's offset without borders (offset + border)
       
   359 				+ ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
       
   360 			),
       
   361 			left: (
       
   362 				pageX																// The absolute mouse position
       
   363 				- this.offset.click.left												// Click offset (relative to the element)
       
   364 				- this.offset.relative.left												// Only for relative positioned nodes: Relative offset from element to offset parent
       
   365 				- this.offset.parent.left												// The offsetParent's offset without borders (offset + border)
       
   366 				+ ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
       
   367 			)
       
   368 		};
       
   369 
   328 	},
   370 	},
   329 
   371 
   330 	_clear: function() {
   372 	_clear: function() {
   331 		this.helper.removeClass("ui-draggable-dragging");
   373 		this.helper.removeClass("ui-draggable-dragging");
   332 		if(this.helper[0] != this.element[0] && !this.cancelHelperRemoval) this.helper.remove();
   374 		if(this.helper[0] != this.element[0] && !this.cancelHelperRemoval) this.helper.remove();
   335 		this.cancelHelperRemoval = false;
   377 		this.cancelHelperRemoval = false;
   336 	},
   378 	},
   337 
   379 
   338 	// From now on bulk stuff - mainly helpers
   380 	// From now on bulk stuff - mainly helpers
   339 
   381 
   340 	_propagate: function(n, event) {
   382 	_trigger: function(type, event, ui) {
   341 		$.ui.plugin.call(this, n, [event, this._uiHash()]);
   383 		ui = ui || this._uiHash();
   342 		if(n == "drag") this.positionAbs = this._convertPositionTo("absolute"); //The absolute position has to be recalculated after plugins
   384 		$.ui.plugin.call(this, type, [event, ui]);
   343 		return this.element.triggerHandler(n == "drag" ? n : "drag"+n, [event, this._uiHash()], this.options[n]);
   385 		if(type == "drag") this.positionAbs = this._convertPositionTo("absolute"); //The absolute position has to be recalculated after plugins
       
   386 		return $.widget.prototype._trigger.call(this, type, event, ui);
   344 	},
   387 	},
   345 
   388 
   346 	plugins: {},
   389 	plugins: {},
   347 
   390 
   348 	_uiHash: function(event) {
   391 	_uiHash: function(event) {
   349 		return {
   392 		return {
   350 			helper: this.helper,
   393 			helper: this.helper,
   351 			position: this.position,
   394 			position: this.position,
   352 			absolutePosition: this.positionAbs,
   395 			absolutePosition: this.positionAbs, //deprecated
   353 			options: this.options
   396 			offset: this.positionAbs
   354 		};
   397 		};
   355 	}
   398 	}
   356 
   399 
   357 }));
   400 }));
   358 
   401 
   359 $.extend($.ui.draggable, {
   402 $.extend($.ui.draggable, {
   360 	version: "1.6",
   403 	version: "1.7.2",
       
   404 	eventPrefix: "drag",
   361 	defaults: {
   405 	defaults: {
       
   406 		addClasses: true,
   362 		appendTo: "parent",
   407 		appendTo: "parent",
   363 		axis: false,
   408 		axis: false,
   364 		cancel: ":input",
   409 		cancel: ":input,option",
   365 		connectToSortable: false,
   410 		connectToSortable: false,
   366 		containment: false,
   411 		containment: false,
   367 		cssNamespace: "ui",
   412 		cursor: "auto",
   368 		cursor: "default",
   413 		cursorAt: false,
   369 		cursorAt: null,
       
   370 		delay: 0,
   414 		delay: 0,
   371 		distance: 1,
   415 		distance: 1,
   372 		grid: false,
   416 		grid: false,
   373 		handle: false,
   417 		handle: false,
   374 		helper: "original",
   418 		helper: "original",
   375 		iframeFix: false,
   419 		iframeFix: false,
   376 		opacity: 1,
   420 		opacity: false,
   377 		refreshPositions: false,
   421 		refreshPositions: false,
   378 		revert: false,
   422 		revert: false,
   379 		revertDuration: 500,
   423 		revertDuration: 500,
   380 		scope: "default",
   424 		scope: "default",
   381 		scroll: true,
   425 		scroll: true,
   383 		scrollSpeed: 20,
   427 		scrollSpeed: 20,
   384 		snap: false,
   428 		snap: false,
   385 		snapMode: "both",
   429 		snapMode: "both",
   386 		snapTolerance: 20,
   430 		snapTolerance: 20,
   387 		stack: false,
   431 		stack: false,
   388 		zIndex: null
   432 		zIndex: false
   389 	}
   433 	}
   390 });
   434 });
   391 
   435 
   392 $.ui.plugin.add("draggable", "connectToSortable", {
   436 $.ui.plugin.add("draggable", "connectToSortable", {
   393 	start: function(event, ui) {
   437 	start: function(event, ui) {
   394 
   438 
   395 		var inst = $(this).data("draggable");
   439 		var inst = $(this).data("draggable"), o = inst.options,
       
   440 			uiSortable = $.extend({}, ui, { item: inst.element });
   396 		inst.sortables = [];
   441 		inst.sortables = [];
   397 		$(ui.options.connectToSortable).each(function() {
   442 		$(o.connectToSortable).each(function() {
   398 			// 'this' points to a string, and should therefore resolved as query, but instead, if the string is assigned to a variable, it loops through the strings properties,
   443 			var sortable = $.data(this, 'sortable');
   399 			// so we have to append '' to make it anonymous again
   444 			if (sortable && !sortable.options.disabled) {
   400 			$(this+'').each(function() {
   445 				inst.sortables.push({
   401 				if($.data(this, 'sortable')) {
   446 					instance: sortable,
   402 					var sortable = $.data(this, 'sortable');
   447 					shouldRevert: sortable.options.revert
   403 					inst.sortables.push({
   448 				});
   404 						instance: sortable,
   449 				sortable._refreshItems();	//Do a one-time refresh at start to refresh the containerCache
   405 						shouldRevert: sortable.options.revert
   450 				sortable._trigger("activate", event, uiSortable);
   406 					});
   451 			}
   407 					sortable._refreshItems();	//Do a one-time refresh at start to refresh the containerCache
       
   408 					sortable._propagate("activate", event, inst);
       
   409 				}
       
   410 			});
       
   411 		});
   452 		});
   412 
   453 
   413 	},
   454 	},
   414 	stop: function(event, ui) {
   455 	stop: function(event, ui) {
   415 
   456 
   416 		//If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
   457 		//If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
   417 		var inst = $(this).data("draggable");
   458 		var inst = $(this).data("draggable"),
       
   459 			uiSortable = $.extend({}, ui, { item: inst.element });
   418 
   460 
   419 		$.each(inst.sortables, function() {
   461 		$.each(inst.sortables, function() {
   420 			if(this.instance.isOver) {
   462 			if(this.instance.isOver) {
       
   463 
   421 				this.instance.isOver = 0;
   464 				this.instance.isOver = 0;
       
   465 
   422 				inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
   466 				inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
   423 				this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
   467 				this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
   424 				if(this.shouldRevert) this.instance.options.revert = true; //revert here
   468 
       
   469 				//The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: 'valid/invalid'
       
   470 				if(this.shouldRevert) this.instance.options.revert = true;
       
   471 
       
   472 				//Trigger the stop of the sortable
   425 				this.instance._mouseStop(event);
   473 				this.instance._mouseStop(event);
   426 
   474 
   427 				//Also propagate receive event, since the sortable is actually receiving a element
       
   428 				this.instance.element.triggerHandler("sortreceive", [event, $.extend(this.instance._ui(), { sender: inst.element })], this.instance.options["receive"]);
       
   429 
       
   430 				this.instance.options.helper = this.instance.options._helper;
   475 				this.instance.options.helper = this.instance.options._helper;
   431 				
   476 
   432 				if(inst.options.helper == 'original') {
   477 				//If the helper has been the original item, restore properties in the sortable
       
   478 				if(inst.options.helper == 'original')
   433 					this.instance.currentItem.css({ top: 'auto', left: 'auto' });
   479 					this.instance.currentItem.css({ top: 'auto', left: 'auto' });
   434 				}
       
   435 
   480 
   436 			} else {
   481 			} else {
   437 				this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance
   482 				this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance
   438 				this.instance._propagate("deactivate", event, inst);
   483 				this.instance._trigger("deactivate", event, uiSortable);
   439 			}
   484 			}
   440 
   485 
   441 		});
   486 		});
   442 
   487 
   443 	},
   488 	},
   453 
   498 
   454 			return $.ui.isOver(helperTop + dyClick, helperLeft + dxClick, itemTop, itemLeft, itemHeight, itemWidth);
   499 			return $.ui.isOver(helperTop + dyClick, helperLeft + dxClick, itemTop, itemLeft, itemHeight, itemWidth);
   455 		};
   500 		};
   456 
   501 
   457 		$.each(inst.sortables, function(i) {
   502 		$.each(inst.sortables, function(i) {
   458 
   503 			
   459 			if(checkPos.call(inst, this.instance.containerCache)) {
   504 			//Copy over some variables to allow calling the sortable's native _intersectsWith
       
   505 			this.instance.positionAbs = inst.positionAbs;
       
   506 			this.instance.helperProportions = inst.helperProportions;
       
   507 			this.instance.offset.click = inst.offset.click;
       
   508 			
       
   509 			if(this.instance._intersectsWith(this.instance.containerCache)) {
   460 
   510 
   461 				//If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
   511 				//If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
   462 				if(!this.instance.isOver) {
   512 				if(!this.instance.isOver) {
       
   513 
   463 					this.instance.isOver = 1;
   514 					this.instance.isOver = 1;
   464 					//Now we fake the start of dragging for the sortable instance,
   515 					//Now we fake the start of dragging for the sortable instance,
   465 					//by cloning the list group item, appending it to the sortable and using it as inst.currentItem
   516 					//by cloning the list group item, appending it to the sortable and using it as inst.currentItem
   466 					//We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one)
   517 					//We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one)
   467 					this.instance.currentItem = $(self).clone().appendTo(this.instance.element).data("sortable-item", true);
   518 					this.instance.currentItem = $(self).clone().appendTo(this.instance.element).data("sortable-item", true);
   476 					this.instance.offset.click.top = inst.offset.click.top;
   527 					this.instance.offset.click.top = inst.offset.click.top;
   477 					this.instance.offset.click.left = inst.offset.click.left;
   528 					this.instance.offset.click.left = inst.offset.click.left;
   478 					this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left;
   529 					this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left;
   479 					this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top;
   530 					this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top;
   480 
   531 
   481 					inst._propagate("toSortable", event);
   532 					inst._trigger("toSortable", event);
       
   533 					inst.dropped = this.instance.element; //draggable revert needs that
       
   534 					//hack so receive/update callbacks work (mostly)
       
   535 					inst.currentItem = inst.element;
       
   536 					this.instance.fromOutside = inst;
   482 
   537 
   483 				}
   538 				}
   484 
   539 
   485 				//Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable
   540 				//Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable
   486 				if(this.instance.currentItem) this.instance._mouseDrag(event);
   541 				if(this.instance.currentItem) this.instance._mouseDrag(event);
   488 			} else {
   543 			} else {
   489 
   544 
   490 				//If it doesn't intersect with the sortable, and it intersected before,
   545 				//If it doesn't intersect with the sortable, and it intersected before,
   491 				//we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
   546 				//we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
   492 				if(this.instance.isOver) {
   547 				if(this.instance.isOver) {
       
   548 
   493 					this.instance.isOver = 0;
   549 					this.instance.isOver = 0;
   494 					this.instance.cancelHelperRemoval = true;
   550 					this.instance.cancelHelperRemoval = true;
   495 					this.instance.options.revert = false; //No revert here
   551 					
       
   552 					//Prevent reverting on this forced stop
       
   553 					this.instance.options.revert = false;
       
   554 					
       
   555 					// The out event needs to be triggered independently
       
   556 					this.instance._trigger('out', event, this.instance._uiHash(this.instance));
       
   557 					
   496 					this.instance._mouseStop(event, true);
   558 					this.instance._mouseStop(event, true);
   497 					this.instance.options.helper = this.instance.options._helper;
   559 					this.instance.options.helper = this.instance.options._helper;
   498 
   560 
   499 					//Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
   561 					//Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
   500 					this.instance.currentItem.remove();
   562 					this.instance.currentItem.remove();
   501 					if(this.instance.placeholder) this.instance.placeholder.remove();
   563 					if(this.instance.placeholder) this.instance.placeholder.remove();
   502 
   564 
   503 					inst._propagate("fromSortable", event);
   565 					inst._trigger("fromSortable", event);
       
   566 					inst.dropped = false; //draggable revert needs that
   504 				}
   567 				}
   505 
   568 
   506 			};
   569 			};
   507 
   570 
   508 		});
   571 		});
   510 	}
   573 	}
   511 });
   574 });
   512 
   575 
   513 $.ui.plugin.add("draggable", "cursor", {
   576 $.ui.plugin.add("draggable", "cursor", {
   514 	start: function(event, ui) {
   577 	start: function(event, ui) {
   515 		var t = $('body');
   578 		var t = $('body'), o = $(this).data('draggable').options;
   516 		if (t.css("cursor")) ui.options._cursor = t.css("cursor");
   579 		if (t.css("cursor")) o._cursor = t.css("cursor");
   517 		t.css("cursor", ui.options.cursor);
   580 		t.css("cursor", o.cursor);
   518 	},
   581 	},
   519 	stop: function(event, ui) {
   582 	stop: function(event, ui) {
   520 		if (ui.options._cursor) $('body').css("cursor", ui.options._cursor);
   583 		var o = $(this).data('draggable').options;
       
   584 		if (o._cursor) $('body').css("cursor", o._cursor);
   521 	}
   585 	}
   522 });
   586 });
   523 
   587 
   524 $.ui.plugin.add("draggable", "iframeFix", {
   588 $.ui.plugin.add("draggable", "iframeFix", {
   525 	start: function(event, ui) {
   589 	start: function(event, ui) {
   526 		$(ui.options.iframeFix === true ? "iframe" : ui.options.iframeFix).each(function() {
   590 		var o = $(this).data('draggable').options;
       
   591 		$(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() {
   527 			$('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>')
   592 			$('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>')
   528 			.css({
   593 			.css({
   529 				width: this.offsetWidth+"px", height: this.offsetHeight+"px",
   594 				width: this.offsetWidth+"px", height: this.offsetHeight+"px",
   530 				position: "absolute", opacity: "0.001", zIndex: 1000
   595 				position: "absolute", opacity: "0.001", zIndex: 1000
   531 			})
   596 			})
   538 	}
   603 	}
   539 });
   604 });
   540 
   605 
   541 $.ui.plugin.add("draggable", "opacity", {
   606 $.ui.plugin.add("draggable", "opacity", {
   542 	start: function(event, ui) {
   607 	start: function(event, ui) {
   543 		var t = $(ui.helper);
   608 		var t = $(ui.helper), o = $(this).data('draggable').options;
   544 		if(t.css("opacity")) ui.options._opacity = t.css("opacity");
   609 		if(t.css("opacity")) o._opacity = t.css("opacity");
   545 		t.css('opacity', ui.options.opacity);
   610 		t.css('opacity', o.opacity);
   546 	},
   611 	},
   547 	stop: function(event, ui) {
   612 	stop: function(event, ui) {
   548 		if(ui.options._opacity) $(ui.helper).css('opacity', ui.options._opacity);
   613 		var o = $(this).data('draggable').options;
       
   614 		if(o._opacity) $(ui.helper).css('opacity', o._opacity);
   549 	}
   615 	}
   550 });
   616 });
   551 
   617 
   552 $.ui.plugin.add("draggable", "scroll", {
   618 $.ui.plugin.add("draggable", "scroll", {
   553 	start: function(event, ui) {
   619 	start: function(event, ui) {
   554 		var o = ui.options;
       
   555 		var i = $(this).data("draggable");
   620 		var i = $(this).data("draggable");
   556 
       
   557 		if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset();
   621 		if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset();
   558 
       
   559 	},
   622 	},
   560 	drag: function(event, ui) {
   623 	drag: function(event, ui) {
   561 
   624 
   562 		var o = ui.options, scrolled = false;
   625 		var i = $(this).data("draggable"), o = i.options, scrolled = false;
   563 		var i = $(this).data("draggable");
       
   564 
   626 
   565 		if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') {
   627 		if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') {
   566 
   628 
   567 			if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
   629 			if(!o.axis || o.axis != 'x') {
   568 				i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
   630 				if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
   569 			else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity)
   631 					i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
   570 				i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
   632 				else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity)
   571 
   633 					i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
   572 			if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
   634 			}
   573 				i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
   635 
   574 			else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity)
   636 			if(!o.axis || o.axis != 'y') {
   575 				i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
   637 				if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
       
   638 					i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
       
   639 				else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity)
       
   640 					i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
       
   641 			}
   576 
   642 
   577 		} else {
   643 		} else {
   578 
   644 
   579 			if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
   645 			if(!o.axis || o.axis != 'x') {
   580 				scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
   646 				if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
   581 			else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
   647 					scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
   582 				scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
   648 				else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
   583 
   649 					scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
   584 			if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
   650 			}
   585 				scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
   651 
   586 			else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
   652 			if(!o.axis || o.axis != 'y') {
   587 				scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
   653 				if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
       
   654 					scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
       
   655 				else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
       
   656 					scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
       
   657 			}
   588 
   658 
   589 		}
   659 		}
   590 
   660 
   591 		if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
   661 		if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
   592 			$.ui.ddmanager.prepareOffsets(i, event);
   662 			$.ui.ddmanager.prepareOffsets(i, event);
   593 
   663 
   594 
       
   595 
       
   596 		// This is a special case where we need to modify a offset calculated on start, since the following happened:
       
   597 		// 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
       
   598 		// 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
       
   599 		//    the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
       
   600 		if(scrolled !== false && i.cssPosition == 'absolute' && i.scrollParent[0] != document && $.ui.contains(i.scrollParent[0], i.offsetParent[0])) {
       
   601 			i.offset.parent = i._getParentOffset();
       
   602 			
       
   603 		}
       
   604 		
       
   605 		// This is another very weird special case that only happens for relative elements:
       
   606 		// 1. If the css position is relative
       
   607 		// 2. and the scroll parent is the document or similar to the offset parent
       
   608 		// we have to refresh the relative offset during the scroll so there are no jumps
       
   609 		if(scrolled !== false && i.cssPosition == 'relative' && !(i.scrollParent[0] != document && i.scrollParent[0] != i.offsetParent[0])) {
       
   610 			i.offset.relative = i._getRelativeOffset();
       
   611 		}
       
   612 		
       
   613 
       
   614 	}
   664 	}
   615 });
   665 });
   616 
   666 
   617 $.ui.plugin.add("draggable", "snap", {
   667 $.ui.plugin.add("draggable", "snap", {
   618 	start: function(event, ui) {
   668 	start: function(event, ui) {
   619 
   669 
   620 		var inst = $(this).data("draggable");
   670 		var i = $(this).data("draggable"), o = i.options;
   621 		inst.snapElements = [];
   671 		i.snapElements = [];
   622 
   672 
   623 		$(ui.options.snap.constructor != String ? ( ui.options.snap.items || ':data(draggable)' ) : ui.options.snap).each(function() {
   673 		$(o.snap.constructor != String ? ( o.snap.items || ':data(draggable)' ) : o.snap).each(function() {
   624 			var $t = $(this); var $o = $t.offset();
   674 			var $t = $(this); var $o = $t.offset();
   625 			if(this != inst.element[0]) inst.snapElements.push({
   675 			if(this != i.element[0]) i.snapElements.push({
   626 				item: this,
   676 				item: this,
   627 				width: $t.outerWidth(), height: $t.outerHeight(),
   677 				width: $t.outerWidth(), height: $t.outerHeight(),
   628 				top: $o.top, left: $o.left
   678 				top: $o.top, left: $o.left
   629 			});
   679 			});
   630 		});
   680 		});
   631 
   681 
   632 	},
   682 	},
   633 	drag: function(event, ui) {
   683 	drag: function(event, ui) {
   634 
   684 
   635 		var inst = $(this).data("draggable");
   685 		var inst = $(this).data("draggable"), o = inst.options;
   636 		var d = ui.options.snapTolerance;
   686 		var d = o.snapTolerance;
   637 
   687 
   638 		var x1 = ui.absolutePosition.left, x2 = x1 + inst.helperProportions.width,
   688 		var x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
   639 			y1 = ui.absolutePosition.top, y2 = y1 + inst.helperProportions.height;
   689 			y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
   640 
   690 
   641 		for (var i = inst.snapElements.length - 1; i >= 0; i--){
   691 		for (var i = inst.snapElements.length - 1; i >= 0; i--){
   642 
   692 
   643 			var l = inst.snapElements[i].left, r = l + inst.snapElements[i].width,
   693 			var l = inst.snapElements[i].left, r = l + inst.snapElements[i].width,
   644 				t = inst.snapElements[i].top, b = t + inst.snapElements[i].height;
   694 				t = inst.snapElements[i].top, b = t + inst.snapElements[i].height;
   648 				if(inst.snapElements[i].snapping) (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
   698 				if(inst.snapElements[i].snapping) (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
   649 				inst.snapElements[i].snapping = false;
   699 				inst.snapElements[i].snapping = false;
   650 				continue;
   700 				continue;
   651 			}
   701 			}
   652 
   702 
   653 			if(ui.options.snapMode != 'inner') {
   703 			if(o.snapMode != 'inner') {
   654 				var ts = Math.abs(t - y2) <= d;
   704 				var ts = Math.abs(t - y2) <= d;
   655 				var bs = Math.abs(b - y1) <= d;
   705 				var bs = Math.abs(b - y1) <= d;
   656 				var ls = Math.abs(l - x2) <= d;
   706 				var ls = Math.abs(l - x2) <= d;
   657 				var rs = Math.abs(r - x1) <= d;
   707 				var rs = Math.abs(r - x1) <= d;
   658 				if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top;
   708 				if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
   659 				if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top;
   709 				if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top;
   660 				if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left;
   710 				if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left;
   661 				if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left;
   711 				if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left;
   662 			}
   712 			}
   663 
   713 
   664 			var first = (ts || bs || ls || rs);
   714 			var first = (ts || bs || ls || rs);
   665 
   715 
   666 			if(ui.options.snapMode != 'outer') {
   716 			if(o.snapMode != 'outer') {
   667 				var ts = Math.abs(t - y1) <= d;
   717 				var ts = Math.abs(t - y1) <= d;
   668 				var bs = Math.abs(b - y2) <= d;
   718 				var bs = Math.abs(b - y2) <= d;
   669 				var ls = Math.abs(l - x1) <= d;
   719 				var ls = Math.abs(l - x1) <= d;
   670 				var rs = Math.abs(r - x2) <= d;
   720 				var rs = Math.abs(r - x2) <= d;
   671 				if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top;
   721 				if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top;
   672 				if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top;
   722 				if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
   673 				if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left;
   723 				if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left;
   674 				if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left;
   724 				if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left;
   675 			}
   725 			}
   676 
   726 
   677 			if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first))
   727 			if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first))
   678 				(inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
   728 				(inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
   679 			inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
   729 			inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
   683 	}
   733 	}
   684 });
   734 });
   685 
   735 
   686 $.ui.plugin.add("draggable", "stack", {
   736 $.ui.plugin.add("draggable", "stack", {
   687 	start: function(event, ui) {
   737 	start: function(event, ui) {
   688 		var group = $.makeArray($(ui.options.stack.group)).sort(function(a,b) {
   738 
   689 			return (parseInt($(a).css("zIndex"),10) || ui.options.stack.min) - (parseInt($(b).css("zIndex"),10) || ui.options.stack.min);
   739 		var o = $(this).data("draggable").options;
       
   740 
       
   741 		var group = $.makeArray($(o.stack.group)).sort(function(a,b) {
       
   742 			return (parseInt($(a).css("zIndex"),10) || o.stack.min) - (parseInt($(b).css("zIndex"),10) || o.stack.min);
   690 		});
   743 		});
   691 
   744 
   692 		$(group).each(function(i) {
   745 		$(group).each(function(i) {
   693 			this.style.zIndex = ui.options.stack.min + i;
   746 			this.style.zIndex = o.stack.min + i;
   694 		});
   747 		});
   695 
   748 
   696 		this[0].style.zIndex = ui.options.stack.min + group.length;
   749 		this[0].style.zIndex = o.stack.min + group.length;
       
   750 
   697 	}
   751 	}
   698 });
   752 });
   699 
   753 
   700 $.ui.plugin.add("draggable", "zIndex", {
   754 $.ui.plugin.add("draggable", "zIndex", {
   701 	start: function(event, ui) {
   755 	start: function(event, ui) {
   702 		var t = $(ui.helper);
   756 		var t = $(ui.helper), o = $(this).data("draggable").options;
   703 		if(t.css("zIndex")) ui.options._zIndex = t.css("zIndex");
   757 		if(t.css("zIndex")) o._zIndex = t.css("zIndex");
   704 		t.css('zIndex', ui.options.zIndex);
   758 		t.css('zIndex', o.zIndex);
   705 	},
   759 	},
   706 	stop: function(event, ui) {
   760 	stop: function(event, ui) {
   707 		if(ui.options._zIndex) $(ui.helper).css('zIndex', ui.options._zIndex);
   761 		var o = $(this).data("draggable").options;
       
   762 		if(o._zIndex) $(ui.helper).css('zIndex', o._zIndex);
   708 	}
   763 	}
   709 });
   764 });
   710 
   765 
   711 })(jQuery);
   766 })(jQuery);