2008-06-04 02:34:33 +00:00
/ *
* jQuery UI Draggable
*
* Copyright ( c ) 2008 Paul Bakaus
* Dual licensed under the MIT ( MIT - LICENSE . txt )
* and GPL ( GPL - LICENSE . txt ) licenses .
*
* http : //docs.jquery.com/UI/Draggables
*
* Depends :
* ui . core . js
*
* Revision : $Id : ui . draggable . js 5672 2008 - 05 - 23 04 : 11 : 30 Z braeker $
* /
2008-06-05 12:14:12 +00:00
( function ( $ ) {
2008-06-04 02:34:33 +00:00
$ . widget ( "ui.draggable" , $ . extend ( $ . ui . mouse , {
init : function ( ) {
//Initialize needed constants
var o = this . options ;
//Position the node
if ( o . helper == 'original' && ! ( /(relative|absolute|fixed)/ ) . test ( this . element . css ( 'position' ) ) )
this . element . css ( 'position' , 'relative' ) ;
this . element . addClass ( 'ui-draggable' ) ;
( o . disabled && this . element . addClass ( 'ui-draggable-disabled' ) ) ;
this . mouseInit ( ) ;
} ,
mouseStart : function ( e ) {
var o = this . options ;
if ( this . helper || o . disabled || $ ( e . target ) . is ( '.ui-resizable-handle' ) ) return false ;
var handle = ! this . options . handle || ! $ ( this . options . handle , this . element ) . length ? true : false ;
2008-06-07 23:25:47 +00:00
$ ( this . options . handle , this . element ) . find ( "*" ) . andSelf ( ) . each ( function ( ) {
2008-06-04 02:34:33 +00:00
if ( this == e . target ) handle = true ;
} ) ;
if ( ! handle ) return false ;
if ( $ . ui . ddmanager ) $ . ui . ddmanager . current = this ;
//Create and append the visible helper
this . helper = $ . isFunction ( o . helper ) ? $ ( o . helper . apply ( this . element [ 0 ] , [ e ] ) ) : ( o . helper == 'clone' ? this . element . clone ( ) : this . element ) ;
if ( ! this . helper . parents ( 'body' ) . length ) this . helper . appendTo ( ( o . appendTo == 'parent' ? this . element [ 0 ] . parentNode : o . appendTo ) ) ;
if ( this . helper [ 0 ] != this . element [ 0 ] && ! ( /(fixed|absolute)/ ) . test ( this . helper . css ( "position" ) ) ) this . helper . css ( "position" , "absolute" ) ;
/ *
* - Position generation -
* This block generates everything position related - it ' s the core of draggables .
* /
this . margins = { //Cache the margins
left : ( parseInt ( this . element . css ( "marginLeft" ) , 10 ) || 0 ) ,
top : ( parseInt ( this . element . css ( "marginTop" ) , 10 ) || 0 )
} ;
this . cssPosition = this . helper . css ( "position" ) ; //Store the helper's css position
this . offset = this . element . offset ( ) ; //The element's absolute position on the page
this . offset = { //Substract the margins from the element's absolute offset
top : this . offset . top - this . margins . top ,
left : this . offset . left - this . margins . left
} ;
this . offset . click = { //Where the click happened, relative to the element
left : e . pageX - this . offset . left ,
top : e . pageY - this . offset . top
} ;
this . offsetParent = this . helper . offsetParent ( ) ; var po = this . offsetParent . offset ( ) ; //Get the offsetParent and cache its position
2008-06-07 22:56:56 +00:00
if ( this . offsetParent [ 0 ] == document . body && $ . browser . mozilla ) po = { top : 0 , left : 0 } ; //Ugly FF3 fix
2008-06-04 02:34:33 +00:00
this . offset . parent = { //Store its position plus border
top : po . top + ( parseInt ( this . offsetParent . css ( "borderTopWidth" ) , 10 ) || 0 ) ,
left : po . left + ( parseInt ( this . offsetParent . css ( "borderLeftWidth" ) , 10 ) || 0 )
} ;
var p = this . element . position ( ) ; //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helpers
this . offset . relative = this . cssPosition == "relative" ? {
top : p . top - ( parseInt ( this . helper . css ( "top" ) , 10 ) || 0 ) + this . offsetParent [ 0 ] . scrollTop ,
left : p . left - ( parseInt ( this . helper . css ( "left" ) , 10 ) || 0 ) + this . offsetParent [ 0 ] . scrollLeft
} : { top : 0 , left : 0 } ;
this . originalPosition = this . generatePosition ( e ) ; //Generate the original position
this . helperProportions = { width : this . helper . outerWidth ( ) , height : this . helper . outerHeight ( ) } ; //Cache the helper size
if ( o . cursorAt ) {
2008-06-07 22:56:56 +00:00
if ( o . cursorAt . left != undefined ) this . offset . click . left = o . cursorAt . left + this . margins . left ;
if ( o . cursorAt . right != undefined ) this . offset . click . left = this . helperProportions . width - o . cursorAt . right + this . margins . left ;
if ( o . cursorAt . top != undefined ) this . offset . click . top = o . cursorAt . top + this . margins . top ;
if ( o . cursorAt . bottom != undefined ) this . offset . click . top = this . helperProportions . height - o . cursorAt . bottom + this . margins . top ;
2008-06-04 02:34:33 +00:00
}
/ *
* - Position constraining -
* Here we prepare position constraining like grid and containment .
* /
if ( o . containment ) {
if ( o . containment == 'parent' ) o . containment = this . helper [ 0 ] . parentNode ;
2008-06-07 23:38:03 +00:00
if ( o . containment == 'document' || o . containment == 'window' ) this . containment = [
0 - this . offset . relative . left - this . offset . parent . left ,
0 - this . offset . relative . top - this . offset . parent . top ,
$ ( o . containment == 'document' ? document : window ) . width ( ) - this . offset . relative . left - this . offset . parent . left - this . helperProportions . width - this . margins . left - ( parseInt ( this . element . css ( "marginRight" ) , 10 ) || 0 ) ,
( $ ( o . containment == 'document' ? document : window ) . height ( ) || document . body . parentNode . scrollHeight ) - this . offset . relative . top - this . offset . parent . top - this . helperProportions . height - this . margins . top - ( parseInt ( this . element . css ( "marginBottom" ) , 10 ) || 0 )
] ;
2008-06-04 02:34:33 +00:00
if ( ! ( /^(document|window|parent)$/ ) . test ( o . containment ) ) {
var ce = $ ( o . containment ) [ 0 ] ;
var co = $ ( o . containment ) . offset ( ) ;
this . containment = [
co . left + ( parseInt ( $ ( ce ) . css ( "borderLeftWidth" ) , 10 ) || 0 ) - this . offset . relative . left - this . offset . parent . left ,
co . top + ( parseInt ( $ ( ce ) . css ( "borderTopWidth" ) , 10 ) || 0 ) - this . offset . relative . top - this . offset . parent . top ,
co . left + Math . max ( ce . scrollWidth , ce . offsetWidth ) - ( parseInt ( $ ( ce ) . css ( "borderLeftWidth" ) , 10 ) || 0 ) - this . offset . relative . left - this . offset . parent . left - this . helperProportions . width - this . margins . left - ( parseInt ( this . element . css ( "marginRight" ) , 10 ) || 0 ) ,
co . top + Math . max ( ce . scrollHeight , ce . offsetHeight ) - ( parseInt ( $ ( ce ) . css ( "borderTopWidth" ) , 10 ) || 0 ) - this . offset . relative . top - this . offset . parent . top - this . helperProportions . height - this . margins . top - ( parseInt ( this . element . css ( "marginBottom" ) , 10 ) || 0 )
] ;
}
}
//Call plugins and callbacks
this . propagate ( "start" , e ) ;
this . helperProportions = { width : this . helper . outerWidth ( ) , height : this . helper . outerHeight ( ) } ; //Recache the helper size
if ( $ . ui . ddmanager && ! o . dropBehaviour ) $ . ui . ddmanager . prepareOffsets ( this , e ) ;
this . helper . addClass ( "ui-draggable-dragging" ) ;
this . mouseDrag ( e ) ; //Execute the drag once - this causes the helper not to be visible before getting its correct position
return true ;
} ,
convertPositionTo : function ( d , pos ) {
if ( ! pos ) pos = this . position ;
var mod = d == "absolute" ? 1 : - 1 ;
return {
top : (
pos . top // the calculated relative position
+ this . offset . relative . top * mod // Only for relative positioned nodes: Relative offset from element to offset parent
+ this . offset . parent . top * mod // The offsetParent's offset without borders (offset + border)
- ( this . cssPosition == "fixed" || ( this . cssPosition == "absolute" && this . offsetParent [ 0 ] == document . body ) ? 0 : this . offsetParent [ 0 ] . scrollTop ) * mod // The offsetParent's scroll position, not if the element is fixed
+ ( this . cssPosition == "fixed" ? this . offsetParent [ 0 ] . scrollTop : 0 ) * mod
+ this . margins . top * mod //Add the margin (you don't want the margin counting in intersection methods)
) ,
left : (
pos . left // the calculated relative position
+ this . offset . relative . left * mod // Only for relative positioned nodes: Relative offset from element to offset parent
+ this . offset . parent . left * mod // The offsetParent's offset without borders (offset + border)
- ( this . cssPosition == "fixed" || ( this . cssPosition == "absolute" && this . offsetParent [ 0 ] == document . body ) ? 0 : this . offsetParent [ 0 ] . scrollLeft ) * mod // The offsetParent's scroll position, not if the element is fixed
+ ( this . cssPosition == "fixed" ? this . offsetParent [ 0 ] . scrollLeft : 0 ) * mod
+ this . margins . left * mod //Add the margin (you don't want the margin counting in intersection methods)
)
} ;
} ,
generatePosition : function ( e ) {
var o = this . options ;
var position = {
top : (
e . pageY // The absolute mouse position
- this . offset . click . top // Click offset (relative to the element)
- this . offset . relative . top // Only for relative positioned nodes: Relative offset from element to offset parent
- this . offset . parent . top // The offsetParent's offset without borders (offset + border)
+ ( this . cssPosition == "fixed" || ( this . cssPosition == "absolute" && this . offsetParent [ 0 ] == document . body ) ? 0 : this . offsetParent [ 0 ] . scrollTop ) // The offsetParent's scroll position, not if the element is fixed
- ( this . cssPosition == "fixed" ? this . offsetParent [ 0 ] . scrollTop : 0 )
) ,
left : (
e . pageX // The absolute mouse position
- this . offset . click . left // Click offset (relative to the element)
- this . offset . relative . left // Only for relative positioned nodes: Relative offset from element to offset parent
- this . offset . parent . left // The offsetParent's offset without borders (offset + border)
+ ( this . cssPosition == "fixed" || ( this . cssPosition == "absolute" && this . offsetParent [ 0 ] == document . body ) ? 0 : this . offsetParent [ 0 ] . scrollLeft ) // The offsetParent's scroll position, not if the element is fixed
- ( this . cssPosition == "fixed" ? this . offsetParent [ 0 ] . scrollLeft : 0 )
)
} ;
if ( ! this . originalPosition ) return position ; //If we are not dragging yet, we won't check for options
/ *
* - Position constraining -
* Constrain the position to a mix of grid , containment .
* /
if ( this . containment ) {
if ( position . left < this . containment [ 0 ] ) position . left = this . containment [ 0 ] ;
if ( position . top < this . containment [ 1 ] ) position . top = this . containment [ 1 ] ;
if ( position . left > this . containment [ 2 ] ) position . left = this . containment [ 2 ] ;
if ( position . top > this . containment [ 3 ] ) position . top = this . containment [ 3 ] ;
}
if ( o . grid ) {
var top = this . originalPosition . top + Math . round ( ( position . top - this . originalPosition . top ) / o . grid [ 1 ] ) * o . grid [ 1 ] ;
position . top = this . containment ? ( ! ( top < this . containment [ 1 ] || top > this . containment [ 3 ] ) ? top : ( ! ( top < this . containment [ 1 ] ) ? top - o . grid [ 1 ] : top + o . grid [ 1 ] ) ) : top ;
var left = this . originalPosition . left + Math . round ( ( position . left - this . originalPosition . left ) / o . grid [ 0 ] ) * o . grid [ 0 ] ;
position . left = this . containment ? ( ! ( left < this . containment [ 0 ] || left > this . containment [ 2 ] ) ? left : ( ! ( left < this . containment [ 0 ] ) ? left - o . grid [ 0 ] : left + o . grid [ 0 ] ) ) : left ;
}
return position ;
} ,
mouseDrag : function ( e ) {
//Compute the helpers position
this . position = this . generatePosition ( e ) ;
this . positionAbs = this . convertPositionTo ( "absolute" ) ;
//Call plugins and callbacks and use the resulting position if something is returned
this . position = this . propagate ( "drag" , e ) || this . position ;
2008-06-07 06:10:52 +00:00
if ( ! this . options . axis || this . options . axis != "y" ) this . helper [ 0 ] . style . left = this . position . left + 'px' ;
if ( ! this . options . axis || this . options . axis != "x" ) this . helper [ 0 ] . style . top = this . position . top + 'px' ;
2008-06-04 02:34:33 +00:00
if ( $ . ui . ddmanager ) $ . ui . ddmanager . drag ( this , e ) ;
return false ;
} ,
mouseStop : function ( e ) {
//If we are using droppables, inform the manager about the drop
if ( $ . ui . ddmanager && ! this . options . dropBehaviour )
$ . ui . ddmanager . drop ( this , e ) ;
if ( this . options . revert ) {
var self = this ;
$ ( this . helper ) . animate ( this . originalPosition , parseInt ( this . options . revert , 10 ) || 500 , function ( ) {
self . propagate ( "stop" , e ) ;
self . clear ( ) ;
} ) ;
} else {
this . propagate ( "stop" , e ) ;
this . clear ( ) ;
}
return false ;
} ,
clear : function ( ) {
this . helper . removeClass ( "ui-draggable-dragging" ) ;
if ( this . options . helper != 'original' && ! this . cancelHelperRemoval ) this . helper . remove ( ) ;
if ( $ . ui . ddmanager ) $ . ui . ddmanager . current = null ;
this . helper = null ;
this . cancelHelperRemoval = false ;
} ,
// From now on bulk stuff - mainly helpers
plugins : { } ,
uiHash : function ( e ) {
return {
helper : this . helper ,
position : this . position ,
absolutePosition : this . positionAbs ,
options : this . options
} ;
} ,
propagate : function ( n , e ) {
$ . ui . plugin . call ( this , n , [ e , this . uiHash ( ) ] ) ;
return this . element . triggerHandler ( n == "drag" ? n : "drag" + n , [ e , this . uiHash ( ) ] , this . options [ n ] ) ;
} ,
destroy : function ( ) {
if ( ! this . element . data ( 'draggable' ) ) return ;
this . element . removeData ( "draggable" ) . unbind ( ".draggable" ) . removeClass ( 'ui-draggable' ) ;
this . mouseDestroy ( ) ;
}
} ) ) ;
$ . extend ( $ . ui . draggable , {
defaults : {
2008-06-07 06:10:52 +00:00
appendTo : "parent" ,
axis : false ,
2008-06-04 02:34:33 +00:00
cancel : ":input,button" ,
2008-06-07 06:10:52 +00:00
delay : 0 ,
distance : 0 ,
helper : "original"
2008-06-04 02:34:33 +00:00
}
} ) ;
$ . ui . plugin . add ( "draggable" , "cursor" , {
start : function ( e , ui ) {
var t = $ ( 'body' ) ;
if ( t . css ( "cursor" ) ) ui . options . _cursor = t . css ( "cursor" ) ;
t . css ( "cursor" , ui . options . cursor ) ;
} ,
stop : function ( e , ui ) {
if ( ui . options . _cursor ) $ ( 'body' ) . css ( "cursor" , ui . options . _cursor ) ;
}
} ) ;
$ . ui . plugin . add ( "draggable" , "zIndex" , {
start : function ( e , ui ) {
var t = $ ( ui . helper ) ;
if ( t . css ( "zIndex" ) ) ui . options . _zIndex = t . css ( "zIndex" ) ;
t . css ( 'zIndex' , ui . options . zIndex ) ;
} ,
stop : function ( e , ui ) {
if ( ui . options . _zIndex ) $ ( ui . helper ) . css ( 'zIndex' , ui . options . _zIndex ) ;
}
} ) ;
$ . ui . plugin . add ( "draggable" , "opacity" , {
start : function ( e , ui ) {
var t = $ ( ui . helper ) ;
if ( t . css ( "opacity" ) ) ui . options . _opacity = t . css ( "opacity" ) ;
t . css ( 'opacity' , ui . options . opacity ) ;
} ,
stop : function ( e , ui ) {
if ( ui . options . _opacity ) $ ( ui . helper ) . css ( 'opacity' , ui . options . _opacity ) ;
}
} ) ;
$ . ui . plugin . add ( "draggable" , "iframeFix" , {
start : function ( e , ui ) {
$ ( ui . options . iframeFix === true ? "iframe" : ui . options . iframeFix ) . each ( function ( ) {
$ ( '<div class="ui-draggable-iframeFix" style="background: #fff;"></div>' )
. css ( {
width : this . offsetWidth + "px" , height : this . offsetHeight + "px" ,
position : "absolute" , opacity : "0.001" , zIndex : 1000
} )
. css ( $ ( this ) . offset ( ) )
. appendTo ( "body" ) ;
} ) ;
} ,
stop : function ( e , ui ) {
$ ( "div.DragDropIframeFix" ) . each ( function ( ) { this . parentNode . removeChild ( this ) ; } ) ; //Remove frame helpers
}
} ) ;
$ . ui . plugin . add ( "draggable" , "scroll" , {
start : function ( e , ui ) {
var o = ui . options ;
var i = $ ( this ) . data ( "draggable" ) ;
o . scrollSensitivity = o . scrollSensitivity || 20 ;
o . scrollSpeed = o . scrollSpeed || 20 ;
i . overflowY = function ( el ) {
do { if ( /auto|scroll/ . test ( el . css ( 'overflow' ) ) || ( /auto|scroll/ ) . test ( el . css ( 'overflow-y' ) ) ) return el ; el = el . parent ( ) ; } while ( el [ 0 ] . parentNode ) ;
return $ ( document ) ;
} ( this ) ;
i . overflowX = function ( el ) {
do { if ( /auto|scroll/ . test ( el . css ( 'overflow' ) ) || ( /auto|scroll/ ) . test ( el . css ( 'overflow-x' ) ) ) return el ; el = el . parent ( ) ; } while ( el [ 0 ] . parentNode ) ;
return $ ( document ) ;
} ( this ) ;
if ( i . overflowY [ 0 ] != document && i . overflowY [ 0 ] . tagName != 'HTML' ) i . overflowYOffset = i . overflowY . offset ( ) ;
if ( i . overflowX [ 0 ] != document && i . overflowX [ 0 ] . tagName != 'HTML' ) i . overflowXOffset = i . overflowX . offset ( ) ;
} ,
drag : function ( e , ui ) {
var o = ui . options ;
var i = $ ( this ) . data ( "draggable" ) ;
if ( i . overflowY [ 0 ] != document && i . overflowY [ 0 ] . tagName != 'HTML' ) {
if ( ( i . overflowYOffset . top + i . overflowY [ 0 ] . offsetHeight ) - e . pageY < o . scrollSensitivity )
i . overflowY [ 0 ] . scrollTop = i . overflowY [ 0 ] . scrollTop + o . scrollSpeed ;
if ( e . pageY - i . overflowYOffset . top < o . scrollSensitivity )
i . overflowY [ 0 ] . scrollTop = i . overflowY [ 0 ] . scrollTop - o . scrollSpeed ;
} else {
if ( e . pageY - $ ( document ) . scrollTop ( ) < o . scrollSensitivity )
$ ( document ) . scrollTop ( $ ( document ) . scrollTop ( ) - o . scrollSpeed ) ;
if ( $ ( window ) . height ( ) - ( e . pageY - $ ( document ) . scrollTop ( ) ) < o . scrollSensitivity )
$ ( document ) . scrollTop ( $ ( document ) . scrollTop ( ) + o . scrollSpeed ) ;
}
if ( i . overflowX [ 0 ] != document && i . overflowX [ 0 ] . tagName != 'HTML' ) {
if ( ( i . overflowXOffset . left + i . overflowX [ 0 ] . offsetWidth ) - e . pageX < o . scrollSensitivity )
i . overflowX [ 0 ] . scrollLeft = i . overflowX [ 0 ] . scrollLeft + o . scrollSpeed ;
if ( e . pageX - i . overflowXOffset . left < o . scrollSensitivity )
i . overflowX [ 0 ] . scrollLeft = i . overflowX [ 0 ] . scrollLeft - o . scrollSpeed ;
} else {
if ( e . pageX - $ ( document ) . scrollLeft ( ) < o . scrollSensitivity )
$ ( document ) . scrollLeft ( $ ( document ) . scrollLeft ( ) - o . scrollSpeed ) ;
if ( $ ( window ) . width ( ) - ( e . pageX - $ ( document ) . scrollLeft ( ) ) < o . scrollSensitivity )
$ ( document ) . scrollLeft ( $ ( document ) . scrollLeft ( ) + o . scrollSpeed ) ;
}
}
} ) ;
$ . ui . plugin . add ( "draggable" , "snap" , {
start : function ( e , ui ) {
var inst = $ ( this ) . data ( "draggable" ) ;
inst . snapElements = [ ] ;
$ ( ui . options . snap === true ? '.ui-draggable' : ui . options . snap ) . each ( function ( ) {
var $t = $ ( this ) ; var $o = $t . offset ( ) ;
if ( this != inst . element [ 0 ] ) inst . snapElements . push ( {
item : this ,
width : $t . outerWidth ( ) , height : $t . outerHeight ( ) ,
top : $o . top , left : $o . left
} ) ;
} ) ;
} ,
drag : function ( e , ui ) {
var inst = $ ( this ) . data ( "draggable" ) ;
var d = ui . options . snapTolerance || 20 ;
var x1 = ui . absolutePosition . left , x2 = x1 + inst . helperProportions . width ,
y1 = ui . absolutePosition . top , y2 = y1 + inst . helperProportions . height ;
for ( var i = inst . snapElements . length - 1 ; i >= 0 ; i -- ) {
var l = inst . snapElements [ i ] . left , r = l + inst . snapElements [ i ] . width ,
t = inst . snapElements [ i ] . top , b = t + inst . snapElements [ i ] . height ;
//Yes, I know, this is insane ;)
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 ) ) ) continue ;
if ( ui . options . snapMode != 'inner' ) {
var ts = Math . abs ( t - y2 ) <= 20 ;
var bs = Math . abs ( b - y1 ) <= 20 ;
var ls = Math . abs ( l - x2 ) <= 20 ;
var rs = Math . abs ( r - x1 ) <= 20 ;
if ( ts ) ui . position . top = inst . convertPositionTo ( "relative" , { top : t - inst . helperProportions . height , left : 0 } ) . top ;
if ( bs ) ui . position . top = inst . convertPositionTo ( "relative" , { top : b , left : 0 } ) . top ;
if ( ls ) ui . position . left = inst . convertPositionTo ( "relative" , { top : 0 , left : l - inst . helperProportions . width } ) . left ;
if ( rs ) ui . position . left = inst . convertPositionTo ( "relative" , { top : 0 , left : r } ) . left ;
}
if ( ui . options . snapMode != 'outer' ) {
var ts = Math . abs ( t - y1 ) <= 20 ;
var bs = Math . abs ( b - y2 ) <= 20 ;
var ls = Math . abs ( l - x1 ) <= 20 ;
var rs = Math . abs ( r - x2 ) <= 20 ;
if ( ts ) ui . position . top = inst . convertPositionTo ( "relative" , { top : t , left : 0 } ) . top ;
if ( bs ) ui . position . top = inst . convertPositionTo ( "relative" , { top : b - inst . helperProportions . height , left : 0 } ) . top ;
if ( ls ) ui . position . left = inst . convertPositionTo ( "relative" , { top : 0 , left : l } ) . left ;
if ( rs ) ui . position . left = inst . convertPositionTo ( "relative" , { top : 0 , left : r - inst . helperProportions . width } ) . left ;
}
} ;
}
} ) ;
$ . ui . plugin . add ( "draggable" , "connectToSortable" , {
start : function ( e , ui ) {
var inst = $ ( this ) . data ( "draggable" ) ;
inst . sortables = [ ] ;
$ ( ui . options . connectToSortable ) . each ( function ( ) {
if ( $ . data ( this , 'sortable' ) ) {
var sortable = $ . data ( this , 'sortable' ) ;
inst . sortables . push ( {
instance : sortable ,
shouldRevert : sortable . options . revert
} ) ;
sortable . refresh ( ) ; //Do a one-time refresh at start to refresh the containerCache
sortable . propagate ( "activate" , e , inst ) ;
}
} ) ;
} ,
stop : function ( e , ui ) {
//If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
var inst = $ ( this ) . data ( "draggable" ) ;
$ . each ( inst . sortables , function ( ) {
if ( this . instance . isOver ) {
this . instance . isOver = 0 ;
inst . cancelHelperRemoval = true ; //Don't remove the helper in the draggable instance
this . instance . cancelHelperRemoval = false ; //Remove it in the sortable instance (so sortable plugins like revert still work)
if ( this . shouldRevert ) this . instance . options . revert = true ; //revert here
this . instance . mouseStop ( e ) ;
//Also propagate receive event, since the sortable is actually receiving a element
this . instance . element . triggerHandler ( "sortreceive" , [ e , $ . extend ( this . instance . ui ( ) , { sender : inst . element } ) ] , this . instance . options [ "receive" ] ) ;
this . instance . options . helper = this . instance . options . _helper ;
} else {
this . instance . propagate ( "deactivate" , e , inst ) ;
}
} ) ;
} ,
drag : function ( e , ui ) {
var inst = $ ( this ) . data ( "draggable" ) , self = this ;
var checkPos = function ( o ) {
var l = o . left , r = l + o . width ,
t = o . top , b = t + o . height ;
return ( l < ( this . positionAbs . left + this . offset . click . left ) && ( this . positionAbs . left + this . offset . click . left ) < r
&& t < ( this . positionAbs . top + this . offset . click . top ) && ( this . positionAbs . top + this . offset . click . top ) < b ) ;
} ;
$ . each ( inst . sortables , function ( i ) {
if ( checkPos . call ( inst , this . instance . containerCache ) ) {
//If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
if ( ! this . instance . isOver ) {
this . instance . isOver = 1 ;
//Now we fake the start of dragging for the sortable instance,
//by cloning the list group item, appending it to the sortable and using it as inst.currentItem
//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)
this . instance . currentItem = $ ( self ) . clone ( ) . appendTo ( this . instance . element ) . data ( "sortable-item" , true ) ;
this . instance . options . _helper = this . instance . options . helper ; //Store helper option to later restore it
this . instance . options . helper = function ( ) { return ui . helper [ 0 ] ; } ;
e . target = this . instance . currentItem [ 0 ] ;
this . instance . mouseStart ( e , true , true ) ;
//Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
this . instance . offset . click . top = inst . offset . click . top ;
this . instance . offset . click . left = inst . offset . click . left ;
this . instance . offset . parent . left -= inst . offset . parent . left - this . instance . offset . parent . left ;
this . instance . offset . parent . top -= inst . offset . parent . top - this . instance . offset . parent . top ;
inst . propagate ( "toSortable" , e ) ;
}
//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
if ( this . instance . currentItem ) this . instance . mouseDrag ( e ) ;
} else {
//If it doesn't intersect with the sortable, and it intersected before,
//we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
if ( this . instance . isOver ) {
this . instance . isOver = 0 ;
this . instance . cancelHelperRemoval = true ;
this . instance . options . revert = false ; //No revert here
this . instance . mouseStop ( e , true ) ;
this . instance . options . helper = this . instance . options . _helper ;
//Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
this . instance . currentItem . remove ( ) ;
this . instance . placeholder . remove ( ) ;
inst . propagate ( "fromSortable" , e ) ;
}
} ;
} ) ;
}
} ) ;
$ . ui . plugin . add ( "draggable" , "stack" , {
start : function ( e , ui ) {
var group = $ . makeArray ( $ ( ui . options . stack . group ) ) . sort ( function ( a , b ) {
return ( parseInt ( $ ( a ) . css ( "zIndex" ) , 10 ) || ui . options . stack . min ) - ( parseInt ( $ ( b ) . css ( "zIndex" ) , 10 ) || ui . options . stack . min ) ;
} ) ;
$ ( group ) . each ( function ( i ) {
this . style . zIndex = ui . options . stack . min + i ;
} ) ;
this [ 0 ] . style . zIndex = ui . options . stack . min + group . length ;
}
} ) ;
} ) ( jQuery ) ;