JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
add needed jquery and jquery-ui files
[peach-cgt.git] / external / jquery.ui.draggable.js
1 /*
2  * jQuery UI Draggable 1.8.17
3  *
4  * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
5  * Dual licensed under the MIT or GPL Version 2 licenses.
6  * http://jquery.org/license
7  *
8  * http://docs.jquery.com/UI/Draggables
9  *
10  * Depends:
11  *      jquery.ui.core.js
12  *      jquery.ui.mouse.js
13  *      jquery.ui.widget.js
14  */
15 (function( $, undefined ) {
16
17 $.widget("ui.draggable", $.ui.mouse, {
18         widgetEventPrefix: "drag",
19         options: {
20                 addClasses: true,
21                 appendTo: "parent",
22                 axis: false,
23                 connectToSortable: false,
24                 containment: false,
25                 cursor: "auto",
26                 cursorAt: false,
27                 grid: false,
28                 handle: false,
29                 helper: "original",
30                 iframeFix: false,
31                 opacity: false,
32                 refreshPositions: false,
33                 revert: false,
34                 revertDuration: 500,
35                 scope: "default",
36                 scroll: true,
37                 scrollSensitivity: 20,
38                 scrollSpeed: 20,
39                 snap: false,
40                 snapMode: "both",
41                 snapTolerance: 20,
42                 stack: false,
43                 zIndex: false
44         },
45         _create: function() {
46
47                 if (this.options.helper == 'original' && !(/^(?:r|a|f)/).test(this.element.css("position")))
48                         this.element[0].style.position = 'relative';
49
50                 (this.options.addClasses && this.element.addClass("ui-draggable"));
51                 (this.options.disabled && this.element.addClass("ui-draggable-disabled"));
52
53                 this._mouseInit();
54
55         },
56
57         destroy: function() {
58                 if(!this.element.data('draggable')) return;
59                 this.element
60                         .removeData("draggable")
61                         .unbind(".draggable")
62                         .removeClass("ui-draggable"
63                                 + " ui-draggable-dragging"
64                                 + " ui-draggable-disabled");
65                 this._mouseDestroy();
66
67                 return this;
68         },
69
70         _mouseCapture: function(event) {
71
72                 var o = this.options;
73
74                 // among others, prevent a drag on a resizable-handle
75                 if (this.helper || o.disabled || $(event.target).is('.ui-resizable-handle'))
76                         return false;
77
78                 //Quit if we're not on a valid handle
79                 this.handle = this._getHandle(event);
80                 if (!this.handle)
81                         return false;
82                 
83                 if ( o.iframeFix ) {
84                         $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() {
85                                 $('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>')
86                                 .css({
87                                         width: this.offsetWidth+"px", height: this.offsetHeight+"px",
88                                         position: "absolute", opacity: "0.001", zIndex: 1000
89                                 })
90                                 .css($(this).offset())
91                                 .appendTo("body");
92                         });
93                 }
94
95                 return true;
96
97         },
98
99         _mouseStart: function(event) {
100
101                 var o = this.options;
102
103                 //Create and append the visible helper
104                 this.helper = this._createHelper(event);
105
106                 //Cache the helper size
107                 this._cacheHelperProportions();
108
109                 //If ddmanager is used for droppables, set the global draggable
110                 if($.ui.ddmanager)
111                         $.ui.ddmanager.current = this;
112
113                 /*
114                  * - Position generation -
115                  * This block generates everything position related - it's the core of draggables.
116                  */
117
118                 //Cache the margins of the original element
119                 this._cacheMargins();
120
121                 //Store the helper's css position
122                 this.cssPosition = this.helper.css("position");
123                 this.scrollParent = this.helper.scrollParent();
124
125                 //The element's absolute position on the page minus margins
126                 this.offset = this.positionAbs = this.element.offset();
127                 this.offset = {
128                         top: this.offset.top - this.margins.top,
129                         left: this.offset.left - this.margins.left
130                 };
131
132                 $.extend(this.offset, {
133                         click: { //Where the click happened, relative to the element
134                                 left: event.pageX - this.offset.left,
135                                 top: event.pageY - this.offset.top
136                         },
137                         parent: this._getParentOffset(),
138                         relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
139                 });
140
141                 //Generate the original position
142                 this.originalPosition = this.position = this._generatePosition(event);
143                 this.originalPageX = event.pageX;
144                 this.originalPageY = event.pageY;
145
146                 //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
147                 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
148
149                 //Set a containment if given in the options
150                 if(o.containment)
151                         this._setContainment();
152
153                 //Trigger event + callbacks
154                 if(this._trigger("start", event) === false) {
155                         this._clear();
156                         return false;
157                 }
158
159                 //Recache the helper size
160                 this._cacheHelperProportions();
161
162                 //Prepare the droppable offsets
163                 if ($.ui.ddmanager && !o.dropBehaviour)
164                         $.ui.ddmanager.prepareOffsets(this, event);
165
166                 this.helper.addClass("ui-draggable-dragging");
167                 this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
168                 
169                 //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
170                 if ( $.ui.ddmanager ) $.ui.ddmanager.dragStart(this, event);
171                 
172                 return true;
173         },
174
175         _mouseDrag: function(event, noPropagation) {
176
177                 //Compute the helpers position
178                 this.position = this._generatePosition(event);
179                 this.positionAbs = this._convertPositionTo("absolute");
180
181                 //Call plugins and callbacks and use the resulting position if something is returned
182                 if (!noPropagation) {
183                         var ui = this._uiHash();
184                         if(this._trigger('drag', event, ui) === false) {
185                                 this._mouseUp({});
186                                 return false;
187                         }
188                         this.position = ui.position;
189                 }
190
191                 if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
192                 if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
193                 if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
194
195                 return false;
196         },
197
198         _mouseStop: function(event) {
199
200                 //If we are using droppables, inform the manager about the drop
201                 var dropped = false;
202                 if ($.ui.ddmanager && !this.options.dropBehaviour)
203                         dropped = $.ui.ddmanager.drop(this, event);
204
205                 //if a drop comes from outside (a sortable)
206                 if(this.dropped) {
207                         dropped = this.dropped;
208                         this.dropped = false;
209                 }
210                 
211                 //if the original element is removed, don't bother to continue if helper is set to "original"
212                 if((!this.element[0] || !this.element[0].parentNode) && this.options.helper == "original")
213                         return false;
214
215                 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))) {
216                         var self = this;
217                         $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
218                                 if(self._trigger("stop", event) !== false) {
219                                         self._clear();
220                                 }
221                         });
222                 } else {
223                         if(this._trigger("stop", event) !== false) {
224                                 this._clear();
225                         }
226                 }
227
228                 return false;
229         },
230         
231         _mouseUp: function(event) {
232                 if (this.options.iframeFix === true) {
233                         $("div.ui-draggable-iframeFix").each(function() { 
234                                 this.parentNode.removeChild(this); 
235                         }); //Remove frame helpers
236                 }
237                 
238                 //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003)
239                 if( $.ui.ddmanager ) $.ui.ddmanager.dragStop(this, event);
240                 
241                 return $.ui.mouse.prototype._mouseUp.call(this, event);
242         },
243         
244         cancel: function() {
245                 
246                 if(this.helper.is(".ui-draggable-dragging")) {
247                         this._mouseUp({});
248                 } else {
249                         this._clear();
250                 }
251                 
252                 return this;
253                 
254         },
255
256         _getHandle: function(event) {
257
258                 var handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false;
259                 $(this.options.handle, this.element)
260                         .find("*")
261                         .andSelf()
262                         .each(function() {
263                                 if(this == event.target) handle = true;
264                         });
265
266                 return handle;
267
268         },
269
270         _createHelper: function(event) {
271
272                 var o = this.options;
273                 var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper == 'clone' ? this.element.clone().removeAttr('id') : this.element);
274
275                 if(!helper.parents('body').length)
276                         helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo));
277
278                 if(helper[0] != this.element[0] && !(/(fixed|absolute)/).test(helper.css("position")))
279                         helper.css("position", "absolute");
280
281                 return helper;
282
283         },
284
285         _adjustOffsetFromHelper: function(obj) {
286                 if (typeof obj == 'string') {
287                         obj = obj.split(' ');
288                 }
289                 if ($.isArray(obj)) {
290                         obj = {left: +obj[0], top: +obj[1] || 0};
291                 }
292                 if ('left' in obj) {
293                         this.offset.click.left = obj.left + this.margins.left;
294                 }
295                 if ('right' in obj) {
296                         this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
297                 }
298                 if ('top' in obj) {
299                         this.offset.click.top = obj.top + this.margins.top;
300                 }
301                 if ('bottom' in obj) {
302                         this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
303                 }
304         },
305
306         _getParentOffset: function() {
307
308                 //Get the offsetParent and cache its position
309                 this.offsetParent = this.helper.offsetParent();
310                 var po = this.offsetParent.offset();
311
312                 // This is a special case where we need to modify a offset calculated on start, since the following happened:
313                 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
314                 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
315                 //    the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
316                 if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) {
317                         po.left += this.scrollParent.scrollLeft();
318                         po.top += this.scrollParent.scrollTop();
319                 }
320
321                 if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information
322                 || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix
323                         po = { top: 0, left: 0 };
324
325                 return {
326                         top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
327                         left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
328                 };
329
330         },
331
332         _getRelativeOffset: function() {
333
334                 if(this.cssPosition == "relative") {
335                         var p = this.element.position();
336                         return {
337                                 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
338                                 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
339                         };
340                 } else {
341                         return { top: 0, left: 0 };
342                 }
343
344         },
345
346         _cacheMargins: function() {
347                 this.margins = {
348                         left: (parseInt(this.element.css("marginLeft"),10) || 0),
349                         top: (parseInt(this.element.css("marginTop"),10) || 0),
350                         right: (parseInt(this.element.css("marginRight"),10) || 0),
351                         bottom: (parseInt(this.element.css("marginBottom"),10) || 0)
352                 };
353         },
354
355         _cacheHelperProportions: function() {
356                 this.helperProportions = {
357                         width: this.helper.outerWidth(),
358                         height: this.helper.outerHeight()
359                 };
360         },
361
362         _setContainment: function() {
363
364                 var o = this.options;
365                 if(o.containment == 'parent') o.containment = this.helper[0].parentNode;
366                 if(o.containment == 'document' || o.containment == 'window') this.containment = [
367                         o.containment == 'document' ? 0 : $(window).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
368                         o.containment == 'document' ? 0 : $(window).scrollTop() - this.offset.relative.top - this.offset.parent.top,
369                         (o.containment == 'document' ? 0 : $(window).scrollLeft()) + $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left,
370                         (o.containment == 'document' ? 0 : $(window).scrollTop()) + ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
371                 ];
372
373                 if(!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor != Array) {
374                         var c = $(o.containment);
375                         var ce = c[0]; if(!ce) return;
376                         var co = c.offset();
377                         var over = ($(ce).css("overflow") != 'hidden');
378
379                         this.containment = [
380                                 (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0),
381                                 (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0),
382                                 (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 - this.margins.right,
383                                 (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  - this.margins.bottom
384                         ];
385                         this.relative_container = c;
386
387                 } else if(o.containment.constructor == Array) {
388                         this.containment = o.containment;
389                 }
390
391         },
392
393         _convertPositionTo: function(d, pos) {
394
395                 if(!pos) pos = this.position;
396                 var mod = d == "absolute" ? 1 : -1;
397                 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);
398
399                 return {
400                         top: (
401                                 pos.top                                                                                                                                 // The absolute mouse position
402                                 + this.offset.relative.top * mod                                                                                // Only for relative positioned nodes: Relative offset from element to offset parent
403                                 + this.offset.parent.top * mod                                                                                  // The offsetParent's offset without borders (offset + border)
404                                 - ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
405                         ),
406                         left: (
407                                 pos.left                                                                                                                                // The absolute mouse position
408                                 + this.offset.relative.left * mod                                                                               // Only for relative positioned nodes: Relative offset from element to offset parent
409                                 + this.offset.parent.left * mod                                                                                 // The offsetParent's offset without borders (offset + border)
410                                 - ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
411                         )
412                 };
413
414         },
415
416         _generatePosition: function(event) {
417
418                 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);
419                 var pageX = event.pageX;
420                 var pageY = event.pageY;
421
422                 /*
423                  * - Position constraining -
424                  * Constrain the position to a mix of grid, containment.
425                  */
426
427                 if(this.originalPosition) { //If we are not dragging yet, we won't check for options
428                          var containment;
429                          if(this.containment) {
430                                  if (this.relative_container){
431                                      var co = this.relative_container.offset();
432                                      containment = [ this.containment[0] + co.left,
433                                                      this.containment[1] + co.top,
434                                                      this.containment[2] + co.left,
435                                                      this.containment[3] + co.top ];
436                                  }
437                                  else {
438                                      containment = this.containment;
439                                  }
440
441                                 if(event.pageX - this.offset.click.left < containment[0]) pageX = containment[0] + this.offset.click.left;
442                                 if(event.pageY - this.offset.click.top < containment[1]) pageY = containment[1] + this.offset.click.top;
443                                 if(event.pageX - this.offset.click.left > containment[2]) pageX = containment[2] + this.offset.click.left;
444                                 if(event.pageY - this.offset.click.top > containment[3]) pageY = containment[3] + this.offset.click.top;
445                         }
446
447                         if(o.grid) {
448                                 //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950)
449                                 var top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY;
450                                 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;
451
452                                 var left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX;
453                                 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;
454                         }
455
456                 }
457
458                 return {
459                         top: (
460                                 pageY                                                                                                                           // The absolute mouse position
461                                 - this.offset.click.top                                                                                                 // Click offset (relative to the element)
462                                 - this.offset.relative.top                                                                                              // Only for relative positioned nodes: Relative offset from element to offset parent
463                                 - this.offset.parent.top                                                                                                // The offsetParent's offset without borders (offset + border)
464                                 + ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
465                         ),
466                         left: (
467                                 pageX                                                                                                                           // The absolute mouse position
468                                 - this.offset.click.left                                                                                                // Click offset (relative to the element)
469                                 - this.offset.relative.left                                                                                             // Only for relative positioned nodes: Relative offset from element to offset parent
470                                 - this.offset.parent.left                                                                                               // The offsetParent's offset without borders (offset + border)
471                                 + ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
472                         )
473                 };
474
475         },
476
477         _clear: function() {
478                 this.helper.removeClass("ui-draggable-dragging");
479                 if(this.helper[0] != this.element[0] && !this.cancelHelperRemoval) this.helper.remove();
480                 //if($.ui.ddmanager) $.ui.ddmanager.current = null;
481                 this.helper = null;
482                 this.cancelHelperRemoval = false;
483         },
484
485         // From now on bulk stuff - mainly helpers
486
487         _trigger: function(type, event, ui) {
488                 ui = ui || this._uiHash();
489                 $.ui.plugin.call(this, type, [event, ui]);
490                 if(type == "drag") this.positionAbs = this._convertPositionTo("absolute"); //The absolute position has to be recalculated after plugins
491                 return $.Widget.prototype._trigger.call(this, type, event, ui);
492         },
493
494         plugins: {},
495
496         _uiHash: function(event) {
497                 return {
498                         helper: this.helper,
499                         position: this.position,
500                         originalPosition: this.originalPosition,
501                         offset: this.positionAbs
502                 };
503         }
504
505 });
506
507 $.extend($.ui.draggable, {
508         version: "1.8.17"
509 });
510
511 $.ui.plugin.add("draggable", "connectToSortable", {
512         start: function(event, ui) {
513
514                 var inst = $(this).data("draggable"), o = inst.options,
515                         uiSortable = $.extend({}, ui, { item: inst.element });
516                 inst.sortables = [];
517                 $(o.connectToSortable).each(function() {
518                         var sortable = $.data(this, 'sortable');
519                         if (sortable && !sortable.options.disabled) {
520                                 inst.sortables.push({
521                                         instance: sortable,
522                                         shouldRevert: sortable.options.revert
523                                 });
524                                 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).
525                                 sortable._trigger("activate", event, uiSortable);
526                         }
527                 });
528
529         },
530         stop: function(event, ui) {
531
532                 //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
533                 var inst = $(this).data("draggable"),
534                         uiSortable = $.extend({}, ui, { item: inst.element });
535
536                 $.each(inst.sortables, function() {
537                         if(this.instance.isOver) {
538
539                                 this.instance.isOver = 0;
540
541                                 inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
542                                 this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
543
544                                 //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: 'valid/invalid'
545                                 if(this.shouldRevert) this.instance.options.revert = true;
546
547                                 //Trigger the stop of the sortable
548                                 this.instance._mouseStop(event);
549
550                                 this.instance.options.helper = this.instance.options._helper;
551
552                                 //If the helper has been the original item, restore properties in the sortable
553                                 if(inst.options.helper == 'original')
554                                         this.instance.currentItem.css({ top: 'auto', left: 'auto' });
555
556                         } else {
557                                 this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance
558                                 this.instance._trigger("deactivate", event, uiSortable);
559                         }
560
561                 });
562
563         },
564         drag: function(event, ui) {
565
566                 var inst = $(this).data("draggable"), self = this;
567
568                 var checkPos = function(o) {
569                         var dyClick = this.offset.click.top, dxClick = this.offset.click.left;
570                         var helperTop = this.positionAbs.top, helperLeft = this.positionAbs.left;
571                         var itemHeight = o.height, itemWidth = o.width;
572                         var itemTop = o.top, itemLeft = o.left;
573
574                         return $.ui.isOver(helperTop + dyClick, helperLeft + dxClick, itemTop, itemLeft, itemHeight, itemWidth);
575                 };
576
577                 $.each(inst.sortables, function(i) {
578                         
579                         //Copy over some variables to allow calling the sortable's native _intersectsWith
580                         this.instance.positionAbs = inst.positionAbs;
581                         this.instance.helperProportions = inst.helperProportions;
582                         this.instance.offset.click = inst.offset.click;
583                         
584                         if(this.instance._intersectsWith(this.instance.containerCache)) {
585
586                                 //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
587                                 if(!this.instance.isOver) {
588
589                                         this.instance.isOver = 1;
590                                         //Now we fake the start of dragging for the sortable instance,
591                                         //by cloning the list group item, appending it to the sortable and using it as inst.currentItem
592                                         //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)
593                                         this.instance.currentItem = $(self).clone().removeAttr('id').appendTo(this.instance.element).data("sortable-item", true);
594                                         this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it
595                                         this.instance.options.helper = function() { return ui.helper[0]; };
596
597                                         event.target = this.instance.currentItem[0];
598                                         this.instance._mouseCapture(event, true);
599                                         this.instance._mouseStart(event, true, true);
600
601                                         //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
602                                         this.instance.offset.click.top = inst.offset.click.top;
603                                         this.instance.offset.click.left = inst.offset.click.left;
604                                         this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left;
605                                         this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top;
606
607                                         inst._trigger("toSortable", event);
608                                         inst.dropped = this.instance.element; //draggable revert needs that
609                                         //hack so receive/update callbacks work (mostly)
610                                         inst.currentItem = inst.element;
611                                         this.instance.fromOutside = inst;
612
613                                 }
614
615                                 //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
616                                 if(this.instance.currentItem) this.instance._mouseDrag(event);
617
618                         } else {
619
620                                 //If it doesn't intersect with the sortable, and it intersected before,
621                                 //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
622                                 if(this.instance.isOver) {
623
624                                         this.instance.isOver = 0;
625                                         this.instance.cancelHelperRemoval = true;
626                                         
627                                         //Prevent reverting on this forced stop
628                                         this.instance.options.revert = false;
629                                         
630                                         // The out event needs to be triggered independently
631                                         this.instance._trigger('out', event, this.instance._uiHash(this.instance));
632                                         
633                                         this.instance._mouseStop(event, true);
634                                         this.instance.options.helper = this.instance.options._helper;
635
636                                         //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
637                                         this.instance.currentItem.remove();
638                                         if(this.instance.placeholder) this.instance.placeholder.remove();
639
640                                         inst._trigger("fromSortable", event);
641                                         inst.dropped = false; //draggable revert needs that
642                                 }
643
644                         };
645
646                 });
647
648         }
649 });
650
651 $.ui.plugin.add("draggable", "cursor", {
652         start: function(event, ui) {
653                 var t = $('body'), o = $(this).data('draggable').options;
654                 if (t.css("cursor")) o._cursor = t.css("cursor");
655                 t.css("cursor", o.cursor);
656         },
657         stop: function(event, ui) {
658                 var o = $(this).data('draggable').options;
659                 if (o._cursor) $('body').css("cursor", o._cursor);
660         }
661 });
662
663 $.ui.plugin.add("draggable", "opacity", {
664         start: function(event, ui) {
665                 var t = $(ui.helper), o = $(this).data('draggable').options;
666                 if(t.css("opacity")) o._opacity = t.css("opacity");
667                 t.css('opacity', o.opacity);
668         },
669         stop: function(event, ui) {
670                 var o = $(this).data('draggable').options;
671                 if(o._opacity) $(ui.helper).css('opacity', o._opacity);
672         }
673 });
674
675 $.ui.plugin.add("draggable", "scroll", {
676         start: function(event, ui) {
677                 var i = $(this).data("draggable");
678                 if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset();
679         },
680         drag: function(event, ui) {
681
682                 var i = $(this).data("draggable"), o = i.options, scrolled = false;
683
684                 if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') {
685
686                         if(!o.axis || o.axis != 'x') {
687                                 if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
688                                         i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
689                                 else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity)
690                                         i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
691                         }
692
693                         if(!o.axis || o.axis != 'y') {
694                                 if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
695                                         i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
696                                 else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity)
697                                         i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
698                         }
699
700                 } else {
701
702                         if(!o.axis || o.axis != 'x') {
703                                 if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
704                                         scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
705                                 else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
706                                         scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
707                         }
708
709                         if(!o.axis || o.axis != 'y') {
710                                 if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
711                                         scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
712                                 else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
713                                         scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
714                         }
715
716                 }
717
718                 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
719                         $.ui.ddmanager.prepareOffsets(i, event);
720
721         }
722 });
723
724 $.ui.plugin.add("draggable", "snap", {
725         start: function(event, ui) {
726
727                 var i = $(this).data("draggable"), o = i.options;
728                 i.snapElements = [];
729
730                 $(o.snap.constructor != String ? ( o.snap.items || ':data(draggable)' ) : o.snap).each(function() {
731                         var $t = $(this); var $o = $t.offset();
732                         if(this != i.element[0]) i.snapElements.push({
733                                 item: this,
734                                 width: $t.outerWidth(), height: $t.outerHeight(),
735                                 top: $o.top, left: $o.left
736                         });
737                 });
738
739         },
740         drag: function(event, ui) {
741
742                 var inst = $(this).data("draggable"), o = inst.options;
743                 var d = o.snapTolerance;
744
745                 var x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
746                         y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
747
748                 for (var i = inst.snapElements.length - 1; i >= 0; i--){
749
750                         var l = inst.snapElements[i].left, r = l + inst.snapElements[i].width,
751                                 t = inst.snapElements[i].top, b = t + inst.snapElements[i].height;
752
753                         //Yes, I know, this is insane ;)
754                         if(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 < b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d) || (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) || (l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) {
755                                 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 })));
756                                 inst.snapElements[i].snapping = false;
757                                 continue;
758                         }
759
760                         if(o.snapMode != 'inner') {
761                                 var ts = Math.abs(t - y2) <= d;
762                                 var bs = Math.abs(b - y1) <= d;
763                                 var ls = Math.abs(l - x2) <= d;
764                                 var rs = Math.abs(r - x1) <= d;
765                                 if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
766                                 if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top;
767                                 if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left;
768                                 if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left;
769                         }
770
771                         var first = (ts || bs || ls || rs);
772
773                         if(o.snapMode != 'outer') {
774                                 var ts = Math.abs(t - y1) <= d;
775                                 var bs = Math.abs(b - y2) <= d;
776                                 var ls = Math.abs(l - x1) <= d;
777                                 var rs = Math.abs(r - x2) <= d;
778                                 if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top;
779                                 if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
780                                 if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left;
781                                 if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left;
782                         }
783
784                         if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first))
785                                 (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
786                         inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
787
788                 };
789
790         }
791 });
792
793 $.ui.plugin.add("draggable", "stack", {
794         start: function(event, ui) {
795
796                 var o = $(this).data("draggable").options;
797
798                 var group = $.makeArray($(o.stack)).sort(function(a,b) {
799                         return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0);
800                 });
801                 if (!group.length) { return; }
802                 
803                 var min = parseInt(group[0].style.zIndex) || 0;
804                 $(group).each(function(i) {
805                         this.style.zIndex = min + i;
806                 });
807
808                 this[0].style.zIndex = min + group.length;
809
810         }
811 });
812
813 $.ui.plugin.add("draggable", "zIndex", {
814         start: function(event, ui) {
815                 var t = $(ui.helper), o = $(this).data("draggable").options;
816                 if(t.css("zIndex")) o._zIndex = t.css("zIndex");
817                 t.css('zIndex', o.zIndex);
818         },
819         stop: function(event, ui) {
820                 var o = $(this).data("draggable").options;
821                 if(o._zIndex) $(ui.helper).css('zIndex', o._zIndex);
822         }
823 });
824
825 })(jQuery);