Brought in following assets that Kevin's EDI project will be using:
[openemr.git] / public / assets / jquery-ui-1-10-4 / ui / jquery.ui.draggable.js
blobd3281dc4f8ea2d9c77e4d2a6901db4ec935a82b5
1 /*!
2  * jQuery UI Draggable 1.10.4
3  * http://jqueryui.com
4  *
5  * Copyright 2014 jQuery Foundation and other contributors
6  * Released under the MIT license.
7  * http://jquery.org/license
8  *
9  * http://api.jqueryui.com/draggable/
10  *
11  * Depends:
12  *      jquery.ui.core.js
13  *      jquery.ui.mouse.js
14  *      jquery.ui.widget.js
15  */
16 (function( $, undefined ) {
18 $.widget("ui.draggable", $.ui.mouse, {
19         version: "1.10.4",
20         widgetEventPrefix: "drag",
21         options: {
22                 addClasses: true,
23                 appendTo: "parent",
24                 axis: false,
25                 connectToSortable: false,
26                 containment: false,
27                 cursor: "auto",
28                 cursorAt: false,
29                 grid: false,
30                 handle: false,
31                 helper: "original",
32                 iframeFix: false,
33                 opacity: false,
34                 refreshPositions: false,
35                 revert: false,
36                 revertDuration: 500,
37                 scope: "default",
38                 scroll: true,
39                 scrollSensitivity: 20,
40                 scrollSpeed: 20,
41                 snap: false,
42                 snapMode: "both",
43                 snapTolerance: 20,
44                 stack: false,
45                 zIndex: false,
47                 // callbacks
48                 drag: null,
49                 start: null,
50                 stop: null
51         },
52         _create: function() {
54                 if (this.options.helper === "original" && !(/^(?:r|a|f)/).test(this.element.css("position"))) {
55                         this.element[0].style.position = "relative";
56                 }
57                 if (this.options.addClasses){
58                         this.element.addClass("ui-draggable");
59                 }
60                 if (this.options.disabled){
61                         this.element.addClass("ui-draggable-disabled");
62                 }
64                 this._mouseInit();
66         },
68         _destroy: function() {
69                 this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" );
70                 this._mouseDestroy();
71         },
73         _mouseCapture: function(event) {
75                 var o = this.options;
77                 // among others, prevent a drag on a resizable-handle
78                 if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) {
79                         return false;
80                 }
82                 //Quit if we're not on a valid handle
83                 this.handle = this._getHandle(event);
84                 if (!this.handle) {
85                         return false;
86                 }
88                 $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() {
89                         $("<div class='ui-draggable-iframeFix' style='background: #fff;'></div>")
90                         .css({
91                                 width: this.offsetWidth+"px", height: this.offsetHeight+"px",
92                                 position: "absolute", opacity: "0.001", zIndex: 1000
93                         })
94                         .css($(this).offset())
95                         .appendTo("body");
96                 });
98                 return true;
100         },
102         _mouseStart: function(event) {
104                 var o = this.options;
106                 //Create and append the visible helper
107                 this.helper = this._createHelper(event);
109                 this.helper.addClass("ui-draggable-dragging");
111                 //Cache the helper size
112                 this._cacheHelperProportions();
114                 //If ddmanager is used for droppables, set the global draggable
115                 if($.ui.ddmanager) {
116                         $.ui.ddmanager.current = this;
117                 }
119                 /*
120                  * - Position generation -
121                  * This block generates everything position related - it's the core of draggables.
122                  */
124                 //Cache the margins of the original element
125                 this._cacheMargins();
127                 //Store the helper's css position
128                 this.cssPosition = this.helper.css( "position" );
129                 this.scrollParent = this.helper.scrollParent();
130                 this.offsetParent = this.helper.offsetParent();
131                 this.offsetParentCssPosition = this.offsetParent.css( "position" );
133                 //The element's absolute position on the page minus margins
134                 this.offset = this.positionAbs = this.element.offset();
135                 this.offset = {
136                         top: this.offset.top - this.margins.top,
137                         left: this.offset.left - this.margins.left
138                 };
140                 //Reset scroll cache
141                 this.offset.scroll = false;
143                 $.extend(this.offset, {
144                         click: { //Where the click happened, relative to the element
145                                 left: event.pageX - this.offset.left,
146                                 top: event.pageY - this.offset.top
147                         },
148                         parent: this._getParentOffset(),
149                         relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
150                 });
152                 //Generate the original position
153                 this.originalPosition = this.position = this._generatePosition(event);
154                 this.originalPageX = event.pageX;
155                 this.originalPageY = event.pageY;
157                 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
158                 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
160                 //Set a containment if given in the options
161                 this._setContainment();
163                 //Trigger event + callbacks
164                 if(this._trigger("start", event) === false) {
165                         this._clear();
166                         return false;
167                 }
169                 //Recache the helper size
170                 this._cacheHelperProportions();
172                 //Prepare the droppable offsets
173                 if ($.ui.ddmanager && !o.dropBehaviour) {
174                         $.ui.ddmanager.prepareOffsets(this, event);
175                 }
178                 this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
180                 //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
181                 if ( $.ui.ddmanager ) {
182                         $.ui.ddmanager.dragStart(this, event);
183                 }
185                 return true;
186         },
188         _mouseDrag: function(event, noPropagation) {
189                 // reset any necessary cached properties (see #5009)
190                 if ( this.offsetParentCssPosition === "fixed" ) {
191                         this.offset.parent = this._getParentOffset();
192                 }
194                 //Compute the helpers position
195                 this.position = this._generatePosition(event);
196                 this.positionAbs = this._convertPositionTo("absolute");
198                 //Call plugins and callbacks and use the resulting position if something is returned
199                 if (!noPropagation) {
200                         var ui = this._uiHash();
201                         if(this._trigger("drag", event, ui) === false) {
202                                 this._mouseUp({});
203                                 return false;
204                         }
205                         this.position = ui.position;
206                 }
208                 if(!this.options.axis || this.options.axis !== "y") {
209                         this.helper[0].style.left = this.position.left+"px";
210                 }
211                 if(!this.options.axis || this.options.axis !== "x") {
212                         this.helper[0].style.top = this.position.top+"px";
213                 }
214                 if($.ui.ddmanager) {
215                         $.ui.ddmanager.drag(this, event);
216                 }
218                 return false;
219         },
221         _mouseStop: function(event) {
223                 //If we are using droppables, inform the manager about the drop
224                 var that = this,
225                         dropped = false;
226                 if ($.ui.ddmanager && !this.options.dropBehaviour) {
227                         dropped = $.ui.ddmanager.drop(this, event);
228                 }
230                 //if a drop comes from outside (a sortable)
231                 if(this.dropped) {
232                         dropped = this.dropped;
233                         this.dropped = false;
234                 }
236                 //if the original element is no longer in the DOM don't bother to continue (see #8269)
237                 if ( this.options.helper === "original" && !$.contains( this.element[ 0 ].ownerDocument, this.element[ 0 ] ) ) {
238                         return false;
239                 }
241                 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))) {
242                         $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
243                                 if(that._trigger("stop", event) !== false) {
244                                         that._clear();
245                                 }
246                         });
247                 } else {
248                         if(this._trigger("stop", event) !== false) {
249                                 this._clear();
250                         }
251                 }
253                 return false;
254         },
256         _mouseUp: function(event) {
257                 //Remove frame helpers
258                 $("div.ui-draggable-iframeFix").each(function() {
259                         this.parentNode.removeChild(this);
260                 });
262                 //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003)
263                 if( $.ui.ddmanager ) {
264                         $.ui.ddmanager.dragStop(this, event);
265                 }
267                 return $.ui.mouse.prototype._mouseUp.call(this, event);
268         },
270         cancel: function() {
272                 if(this.helper.is(".ui-draggable-dragging")) {
273                         this._mouseUp({});
274                 } else {
275                         this._clear();
276                 }
278                 return this;
280         },
282         _getHandle: function(event) {
283                 return this.options.handle ?
284                         !!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
285                         true;
286         },
288         _createHelper: function(event) {
290                 var o = this.options,
291                         helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper === "clone" ? this.element.clone().removeAttr("id") : this.element);
293                 if(!helper.parents("body").length) {
294                         helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo));
295                 }
297                 if(helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) {
298                         helper.css("position", "absolute");
299                 }
301                 return helper;
303         },
305         _adjustOffsetFromHelper: function(obj) {
306                 if (typeof obj === "string") {
307                         obj = obj.split(" ");
308                 }
309                 if ($.isArray(obj)) {
310                         obj = {left: +obj[0], top: +obj[1] || 0};
311                 }
312                 if ("left" in obj) {
313                         this.offset.click.left = obj.left + this.margins.left;
314                 }
315                 if ("right" in obj) {
316                         this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
317                 }
318                 if ("top" in obj) {
319                         this.offset.click.top = obj.top + this.margins.top;
320                 }
321                 if ("bottom" in obj) {
322                         this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
323                 }
324         },
326         _getParentOffset: function() {
328                 //Get the offsetParent and cache its position
329                 var po = this.offsetParent.offset();
331                 // This is a special case where we need to modify a offset calculated on start, since the following happened:
332                 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
333                 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
334                 //    the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
335                 if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
336                         po.left += this.scrollParent.scrollLeft();
337                         po.top += this.scrollParent.scrollTop();
338                 }
340                 //This needs to be actually done for all browsers, since pageX/pageY includes this information
341                 //Ugly IE fix
342                 if((this.offsetParent[0] === document.body) ||
343                         (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
344                         po = { top: 0, left: 0 };
345                 }
347                 return {
348                         top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
349                         left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
350                 };
352         },
354         _getRelativeOffset: function() {
356                 if(this.cssPosition === "relative") {
357                         var p = this.element.position();
358                         return {
359                                 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
360                                 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
361                         };
362                 } else {
363                         return { top: 0, left: 0 };
364                 }
366         },
368         _cacheMargins: function() {
369                 this.margins = {
370                         left: (parseInt(this.element.css("marginLeft"),10) || 0),
371                         top: (parseInt(this.element.css("marginTop"),10) || 0),
372                         right: (parseInt(this.element.css("marginRight"),10) || 0),
373                         bottom: (parseInt(this.element.css("marginBottom"),10) || 0)
374                 };
375         },
377         _cacheHelperProportions: function() {
378                 this.helperProportions = {
379                         width: this.helper.outerWidth(),
380                         height: this.helper.outerHeight()
381                 };
382         },
384         _setContainment: function() {
386                 var over, c, ce,
387                         o = this.options;
389                 if ( !o.containment ) {
390                         this.containment = null;
391                         return;
392                 }
394                 if ( o.containment === "window" ) {
395                         this.containment = [
396                                 $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
397                                 $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
398                                 $( window ).scrollLeft() + $( window ).width() - this.helperProportions.width - this.margins.left,
399                                 $( window ).scrollTop() + ( $( window ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
400                         ];
401                         return;
402                 }
404                 if ( o.containment === "document") {
405                         this.containment = [
406                                 0,
407                                 0,
408                                 $( document ).width() - this.helperProportions.width - this.margins.left,
409                                 ( $( document ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
410                         ];
411                         return;
412                 }
414                 if ( o.containment.constructor === Array ) {
415                         this.containment = o.containment;
416                         return;
417                 }
419                 if ( o.containment === "parent" ) {
420                         o.containment = this.helper[ 0 ].parentNode;
421                 }
423                 c = $( o.containment );
424                 ce = c[ 0 ];
426                 if( !ce ) {
427                         return;
428                 }
430                 over = c.css( "overflow" ) !== "hidden";
432                 this.containment = [
433                         ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
434                         ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ) ,
435                         ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) - ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) - this.helperProportions.width - this.margins.left - this.margins.right,
436                         ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) - ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) - this.helperProportions.height - this.margins.top  - this.margins.bottom
437                 ];
438                 this.relative_container = c;
439         },
441         _convertPositionTo: function(d, pos) {
443                 if(!pos) {
444                         pos = this.position;
445                 }
447                 var mod = d === "absolute" ? 1 : -1,
448                         scroll = this.cssPosition === "absolute" && !( this.scrollParent[ 0 ] !== document && $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? this.offsetParent : this.scrollParent;
450                 //Cache the scroll
451                 if (!this.offset.scroll) {
452                         this.offset.scroll = {top : scroll.scrollTop(), left : scroll.scrollLeft()};
453                 }
455                 return {
456                         top: (
457                                 pos.top +                                                                                                                               // The absolute mouse position
458                                 this.offset.relative.top * mod +                                                                                // Only for relative positioned nodes: Relative offset from element to offset parent
459                                 this.offset.parent.top * mod -                                                                          // The offsetParent's offset without borders (offset + border)
460                                 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : this.offset.scroll.top ) * mod )
461                         ),
462                         left: (
463                                 pos.left +                                                                                                                              // The absolute mouse position
464                                 this.offset.relative.left * mod +                                                                               // Only for relative positioned nodes: Relative offset from element to offset parent
465                                 this.offset.parent.left * mod   -                                                                               // The offsetParent's offset without borders (offset + border)
466                                 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : this.offset.scroll.left ) * mod )
467                         )
468                 };
470         },
472         _generatePosition: function(event) {
474                 var containment, co, top, left,
475                         o = this.options,
476                         scroll = this.cssPosition === "absolute" && !( this.scrollParent[ 0 ] !== document && $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? this.offsetParent : this.scrollParent,
477                         pageX = event.pageX,
478                         pageY = event.pageY;
480                 //Cache the scroll
481                 if (!this.offset.scroll) {
482                         this.offset.scroll = {top : scroll.scrollTop(), left : scroll.scrollLeft()};
483                 }
485                 /*
486                  * - Position constraining -
487                  * Constrain the position to a mix of grid, containment.
488                  */
490                 // If we are not dragging yet, we won't check for options
491                 if ( this.originalPosition ) {
492                         if ( this.containment ) {
493                                 if ( this.relative_container ){
494                                         co = this.relative_container.offset();
495                                         containment = [
496                                                 this.containment[ 0 ] + co.left,
497                                                 this.containment[ 1 ] + co.top,
498                                                 this.containment[ 2 ] + co.left,
499                                                 this.containment[ 3 ] + co.top
500                                         ];
501                                 }
502                                 else {
503                                         containment = this.containment;
504                                 }
506                                 if(event.pageX - this.offset.click.left < containment[0]) {
507                                         pageX = containment[0] + this.offset.click.left;
508                                 }
509                                 if(event.pageY - this.offset.click.top < containment[1]) {
510                                         pageY = containment[1] + this.offset.click.top;
511                                 }
512                                 if(event.pageX - this.offset.click.left > containment[2]) {
513                                         pageX = containment[2] + this.offset.click.left;
514                                 }
515                                 if(event.pageY - this.offset.click.top > containment[3]) {
516                                         pageY = containment[3] + this.offset.click.top;
517                                 }
518                         }
520                         if(o.grid) {
521                                 //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950)
522                                 top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY;
523                                 pageY = containment ? ((top - this.offset.click.top >= containment[1] || top - this.offset.click.top > containment[3]) ? top : ((top - this.offset.click.top >= containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
525                                 left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX;
526                                 pageX = containment ? ((left - this.offset.click.left >= containment[0] || left - this.offset.click.left > containment[2]) ? left : ((left - this.offset.click.left >= containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
527                         }
529                 }
531                 return {
532                         top: (
533                                 pageY -                                                                                                                                 // The absolute mouse position
534                                 this.offset.click.top   -                                                                                               // Click offset (relative to the element)
535                                 this.offset.relative.top -                                                                                              // Only for relative positioned nodes: Relative offset from element to offset parent
536                                 this.offset.parent.top +                                                                                                // The offsetParent's offset without borders (offset + border)
537                                 ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : this.offset.scroll.top )
538                         ),
539                         left: (
540                                 pageX -                                                                                                                                 // The absolute mouse position
541                                 this.offset.click.left -                                                                                                // Click offset (relative to the element)
542                                 this.offset.relative.left -                                                                                             // Only for relative positioned nodes: Relative offset from element to offset parent
543                                 this.offset.parent.left +                                                                                               // The offsetParent's offset without borders (offset + border)
544                                 ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : this.offset.scroll.left )
545                         )
546                 };
548         },
550         _clear: function() {
551                 this.helper.removeClass("ui-draggable-dragging");
552                 if(this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) {
553                         this.helper.remove();
554                 }
555                 this.helper = null;
556                 this.cancelHelperRemoval = false;
557         },
559         // From now on bulk stuff - mainly helpers
561         _trigger: function(type, event, ui) {
562                 ui = ui || this._uiHash();
563                 $.ui.plugin.call(this, type, [event, ui]);
564                 //The absolute position has to be recalculated after plugins
565                 if(type === "drag") {
566                         this.positionAbs = this._convertPositionTo("absolute");
567                 }
568                 return $.Widget.prototype._trigger.call(this, type, event, ui);
569         },
571         plugins: {},
573         _uiHash: function() {
574                 return {
575                         helper: this.helper,
576                         position: this.position,
577                         originalPosition: this.originalPosition,
578                         offset: this.positionAbs
579                 };
580         }
584 $.ui.plugin.add("draggable", "connectToSortable", {
585         start: function(event, ui) {
587                 var inst = $(this).data("ui-draggable"), o = inst.options,
588                         uiSortable = $.extend({}, ui, { item: inst.element });
589                 inst.sortables = [];
590                 $(o.connectToSortable).each(function() {
591                         var sortable = $.data(this, "ui-sortable");
592                         if (sortable && !sortable.options.disabled) {
593                                 inst.sortables.push({
594                                         instance: sortable,
595                                         shouldRevert: sortable.options.revert
596                                 });
597                                 sortable.refreshPositions();    // Call the sortable's refreshPositions at drag start to refresh the containerCache since the sortable container cache is used in drag and needs to be up to date (this will ensure it's initialised as well as being kept in step with any changes that might have happened on the page).
598                                 sortable._trigger("activate", event, uiSortable);
599                         }
600                 });
602         },
603         stop: function(event, ui) {
605                 //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
606                 var inst = $(this).data("ui-draggable"),
607                         uiSortable = $.extend({}, ui, { item: inst.element });
609                 $.each(inst.sortables, function() {
610                         if(this.instance.isOver) {
612                                 this.instance.isOver = 0;
614                                 inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
615                                 this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
617                                 //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: "valid/invalid"
618                                 if(this.shouldRevert) {
619                                         this.instance.options.revert = this.shouldRevert;
620                                 }
622                                 //Trigger the stop of the sortable
623                                 this.instance._mouseStop(event);
625                                 this.instance.options.helper = this.instance.options._helper;
627                                 //If the helper has been the original item, restore properties in the sortable
628                                 if(inst.options.helper === "original") {
629                                         this.instance.currentItem.css({ top: "auto", left: "auto" });
630                                 }
632                         } else {
633                                 this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance
634                                 this.instance._trigger("deactivate", event, uiSortable);
635                         }
637                 });
639         },
640         drag: function(event, ui) {
642                 var inst = $(this).data("ui-draggable"), that = this;
644                 $.each(inst.sortables, function() {
646                         var innermostIntersecting = false,
647                                 thisSortable = this;
649                         //Copy over some variables to allow calling the sortable's native _intersectsWith
650                         this.instance.positionAbs = inst.positionAbs;
651                         this.instance.helperProportions = inst.helperProportions;
652                         this.instance.offset.click = inst.offset.click;
654                         if(this.instance._intersectsWith(this.instance.containerCache)) {
655                                 innermostIntersecting = true;
656                                 $.each(inst.sortables, function () {
657                                         this.instance.positionAbs = inst.positionAbs;
658                                         this.instance.helperProportions = inst.helperProportions;
659                                         this.instance.offset.click = inst.offset.click;
660                                         if (this !== thisSortable &&
661                                                 this.instance._intersectsWith(this.instance.containerCache) &&
662                                                 $.contains(thisSortable.instance.element[0], this.instance.element[0])
663                                         ) {
664                                                 innermostIntersecting = false;
665                                         }
666                                         return innermostIntersecting;
667                                 });
668                         }
671                         if(innermostIntersecting) {
672                                 //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
673                                 if(!this.instance.isOver) {
675                                         this.instance.isOver = 1;
676                                         //Now we fake the start of dragging for the sortable instance,
677                                         //by cloning the list group item, appending it to the sortable and using it as inst.currentItem
678                                         //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)
679                                         this.instance.currentItem = $(that).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item", true);
680                                         this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it
681                                         this.instance.options.helper = function() { return ui.helper[0]; };
683                                         event.target = this.instance.currentItem[0];
684                                         this.instance._mouseCapture(event, true);
685                                         this.instance._mouseStart(event, true, true);
687                                         //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
688                                         this.instance.offset.click.top = inst.offset.click.top;
689                                         this.instance.offset.click.left = inst.offset.click.left;
690                                         this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left;
691                                         this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top;
693                                         inst._trigger("toSortable", event);
694                                         inst.dropped = this.instance.element; //draggable revert needs that
695                                         //hack so receive/update callbacks work (mostly)
696                                         inst.currentItem = inst.element;
697                                         this.instance.fromOutside = inst;
699                                 }
701                                 //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
702                                 if(this.instance.currentItem) {
703                                         this.instance._mouseDrag(event);
704                                 }
706                         } else {
708                                 //If it doesn't intersect with the sortable, and it intersected before,
709                                 //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
710                                 if(this.instance.isOver) {
712                                         this.instance.isOver = 0;
713                                         this.instance.cancelHelperRemoval = true;
715                                         //Prevent reverting on this forced stop
716                                         this.instance.options.revert = false;
718                                         // The out event needs to be triggered independently
719                                         this.instance._trigger("out", event, this.instance._uiHash(this.instance));
721                                         this.instance._mouseStop(event, true);
722                                         this.instance.options.helper = this.instance.options._helper;
724                                         //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
725                                         this.instance.currentItem.remove();
726                                         if(this.instance.placeholder) {
727                                                 this.instance.placeholder.remove();
728                                         }
730                                         inst._trigger("fromSortable", event);
731                                         inst.dropped = false; //draggable revert needs that
732                                 }
734                         }
736                 });
738         }
741 $.ui.plugin.add("draggable", "cursor", {
742         start: function() {
743                 var t = $("body"), o = $(this).data("ui-draggable").options;
744                 if (t.css("cursor")) {
745                         o._cursor = t.css("cursor");
746                 }
747                 t.css("cursor", o.cursor);
748         },
749         stop: function() {
750                 var o = $(this).data("ui-draggable").options;
751                 if (o._cursor) {
752                         $("body").css("cursor", o._cursor);
753                 }
754         }
757 $.ui.plugin.add("draggable", "opacity", {
758         start: function(event, ui) {
759                 var t = $(ui.helper), o = $(this).data("ui-draggable").options;
760                 if(t.css("opacity")) {
761                         o._opacity = t.css("opacity");
762                 }
763                 t.css("opacity", o.opacity);
764         },
765         stop: function(event, ui) {
766                 var o = $(this).data("ui-draggable").options;
767                 if(o._opacity) {
768                         $(ui.helper).css("opacity", o._opacity);
769                 }
770         }
773 $.ui.plugin.add("draggable", "scroll", {
774         start: function() {
775                 var i = $(this).data("ui-draggable");
776                 if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") {
777                         i.overflowOffset = i.scrollParent.offset();
778                 }
779         },
780         drag: function( event ) {
782                 var i = $(this).data("ui-draggable"), o = i.options, scrolled = false;
784                 if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") {
786                         if(!o.axis || o.axis !== "x") {
787                                 if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
788                                         i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
789                                 } else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) {
790                                         i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
791                                 }
792                         }
794                         if(!o.axis || o.axis !== "y") {
795                                 if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
796                                         i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
797                                 } else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) {
798                                         i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
799                                 }
800                         }
802                 } else {
804                         if(!o.axis || o.axis !== "x") {
805                                 if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
806                                         scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
807                                 } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
808                                         scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
809                                 }
810                         }
812                         if(!o.axis || o.axis !== "y") {
813                                 if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
814                                         scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
815                                 } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
816                                         scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
817                                 }
818                         }
820                 }
822                 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
823                         $.ui.ddmanager.prepareOffsets(i, event);
824                 }
826         }
829 $.ui.plugin.add("draggable", "snap", {
830         start: function() {
832                 var i = $(this).data("ui-draggable"),
833                         o = i.options;
835                 i.snapElements = [];
837                 $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() {
838                         var $t = $(this),
839                                 $o = $t.offset();
840                         if(this !== i.element[0]) {
841                                 i.snapElements.push({
842                                         item: this,
843                                         width: $t.outerWidth(), height: $t.outerHeight(),
844                                         top: $o.top, left: $o.left
845                                 });
846                         }
847                 });
849         },
850         drag: function(event, ui) {
852                 var ts, bs, ls, rs, l, r, t, b, i, first,
853                         inst = $(this).data("ui-draggable"),
854                         o = inst.options,
855                         d = o.snapTolerance,
856                         x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
857                         y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
859                 for (i = inst.snapElements.length - 1; i >= 0; i--){
861                         l = inst.snapElements[i].left;
862                         r = l + inst.snapElements[i].width;
863                         t = inst.snapElements[i].top;
864                         b = t + inst.snapElements[i].height;
866                         if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || !$.contains( inst.snapElements[ i ].item.ownerDocument, inst.snapElements[ i ].item ) ) {
867                                 if(inst.snapElements[i].snapping) {
868                                         (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
869                                 }
870                                 inst.snapElements[i].snapping = false;
871                                 continue;
872                         }
874                         if(o.snapMode !== "inner") {
875                                 ts = Math.abs(t - y2) <= d;
876                                 bs = Math.abs(b - y1) <= d;
877                                 ls = Math.abs(l - x2) <= d;
878                                 rs = Math.abs(r - x1) <= d;
879                                 if(ts) {
880                                         ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
881                                 }
882                                 if(bs) {
883                                         ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top;
884                                 }
885                                 if(ls) {
886                                         ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left;
887                                 }
888                                 if(rs) {
889                                         ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left;
890                                 }
891                         }
893                         first = (ts || bs || ls || rs);
895                         if(o.snapMode !== "outer") {
896                                 ts = Math.abs(t - y1) <= d;
897                                 bs = Math.abs(b - y2) <= d;
898                                 ls = Math.abs(l - x1) <= d;
899                                 rs = Math.abs(r - x2) <= d;
900                                 if(ts) {
901                                         ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top;
902                                 }
903                                 if(bs) {
904                                         ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
905                                 }
906                                 if(ls) {
907                                         ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left;
908                                 }
909                                 if(rs) {
910                                         ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left;
911                                 }
912                         }
914                         if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) {
915                                 (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
916                         }
917                         inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
919                 }
921         }
924 $.ui.plugin.add("draggable", "stack", {
925         start: function() {
926                 var min,
927                         o = this.data("ui-draggable").options,
928                         group = $.makeArray($(o.stack)).sort(function(a,b) {
929                                 return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0);
930                         });
932                 if (!group.length) { return; }
934                 min = parseInt($(group[0]).css("zIndex"), 10) || 0;
935                 $(group).each(function(i) {
936                         $(this).css("zIndex", min + i);
937                 });
938                 this.css("zIndex", (min + group.length));
939         }
942 $.ui.plugin.add("draggable", "zIndex", {
943         start: function(event, ui) {
944                 var t = $(ui.helper), o = $(this).data("ui-draggable").options;
945                 if(t.css("zIndex")) {
946                         o._zIndex = t.css("zIndex");
947                 }
948                 t.css("zIndex", o.zIndex);
949         },
950         stop: function(event, ui) {
951                 var o = $(this).data("ui-draggable").options;
952                 if(o._zIndex) {
953                         $(ui.helper).css("zIndex", o._zIndex);
954                 }
955         }
958 })(jQuery);