2 * jQuery UI Droppable 1.8.24
4 * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
5 * Dual licensed under the MIT or GPL Version 2 licenses.
6 * http://jquery.org/license
8 * http://docs.jquery.com/UI/Droppables
14 * jquery.ui.draggable.js
16 (function( $, undefined ) {
18 $.widget("ui.droppable", {
19 widgetEventPrefix
: "drop",
27 tolerance
: 'intersect'
31 var o
= this.options
, accept
= o
.accept
;
32 this.isover
= 0; this.isout
= 1;
34 this.accept
= $.isFunction(accept
) ? accept : function(d
) {
38 //Store the droppable's proportions
39 this.proportions
= { width
: this.element
[0].offsetWidth
, height
: this.element
[0].offsetHeight
};
41 // Add the reference and positions to the manager
42 $.ui
.ddmanager
.droppables
[o
.scope
] = $.ui
.ddmanager
.droppables
[o
.scope
] || [];
43 $.ui
.ddmanager
.droppables
[o
.scope
].push(this);
45 (o
.addClasses
&& this.element
.addClass("ui-droppable"));
50 var drop
= $.ui
.ddmanager
.droppables
[this.options
.scope
];
51 for ( var i
= 0; i
< drop
.length
; i
++ )
52 if ( drop
[i
] == this )
56 .removeClass("ui-droppable ui-droppable-disabled")
57 .removeData("droppable")
58 .unbind(".droppable");
63 _setOption: function(key
, value
) {
66 this.accept
= $.isFunction(value
) ? value : function(d
) {
70 $.Widget
.prototype._setOption
.apply(this, arguments
);
73 _activate: function(event
) {
74 var draggable
= $.ui
.ddmanager
.current
;
75 if(this.options
.activeClass
) this.element
.addClass(this.options
.activeClass
);
76 (draggable
&& this._trigger('activate', event
, this.ui(draggable
)));
79 _deactivate: function(event
) {
80 var draggable
= $.ui
.ddmanager
.current
;
81 if(this.options
.activeClass
) this.element
.removeClass(this.options
.activeClass
);
82 (draggable
&& this._trigger('deactivate', event
, this.ui(draggable
)));
85 _over: function(event
) {
87 var draggable
= $.ui
.ddmanager
.current
;
88 if (!draggable
|| (draggable
.currentItem
|| draggable
.element
)[0] == this.element
[0]) return; // Bail if draggable and droppable are same element
90 if (this.accept
.call(this.element
[0],(draggable
.currentItem
|| draggable
.element
))) {
91 if(this.options
.hoverClass
) this.element
.addClass(this.options
.hoverClass
);
92 this._trigger('over', event
, this.ui(draggable
));
97 _out: function(event
) {
99 var draggable
= $.ui
.ddmanager
.current
;
100 if (!draggable
|| (draggable
.currentItem
|| draggable
.element
)[0] == this.element
[0]) return; // Bail if draggable and droppable are same element
102 if (this.accept
.call(this.element
[0],(draggable
.currentItem
|| draggable
.element
))) {
103 if(this.options
.hoverClass
) this.element
.removeClass(this.options
.hoverClass
);
104 this._trigger('out', event
, this.ui(draggable
));
109 _drop: function(event
,custom
) {
111 var draggable
= custom
|| $.ui
.ddmanager
.current
;
112 if (!draggable
|| (draggable
.currentItem
|| draggable
.element
)[0] == this.element
[0]) return false; // Bail if draggable and droppable are same element
114 var childrenIntersection
= false;
115 this.element
.find(":data(droppable)").not(".ui-draggable-dragging").each(function() {
116 var inst
= $.data(this, 'droppable');
119 && !inst
.options
.disabled
120 && inst
.options
.scope
== draggable
.options
.scope
121 && inst
.accept
.call(inst
.element
[0], (draggable
.currentItem
|| draggable
.element
))
122 && $.ui
.intersect(draggable
, $.extend(inst
, { offset
: inst
.element
.offset() }), inst
.options
.tolerance
)
123 ) { childrenIntersection
= true; return false; }
125 if(childrenIntersection
) return false;
127 if(this.accept
.call(this.element
[0],(draggable
.currentItem
|| draggable
.element
))) {
128 if(this.options
.activeClass
) this.element
.removeClass(this.options
.activeClass
);
129 if(this.options
.hoverClass
) this.element
.removeClass(this.options
.hoverClass
);
130 this._trigger('drop', event
, this.ui(draggable
));
140 draggable
: (c
.currentItem
|| c
.element
),
142 position
: c
.position
,
143 offset
: c
.positionAbs
149 $.extend($.ui
.droppable
, {
153 $.ui
.intersect = function(draggable
, droppable
, toleranceMode
) {
155 if (!droppable
.offset
) return false;
157 var x1
= (draggable
.positionAbs
|| draggable
.position
.absolute
).left
, x2
= x1
+ draggable
.helperProportions
.width
,
158 y1
= (draggable
.positionAbs
|| draggable
.position
.absolute
).top
, y2
= y1
+ draggable
.helperProportions
.height
;
159 var l
= droppable
.offset
.left
, r
= l
+ droppable
.proportions
.width
,
160 t
= droppable
.offset
.top
, b
= t
+ droppable
.proportions
.height
;
162 switch (toleranceMode
) {
164 return (l
<= x1
&& x2
<= r
165 && t
<= y1
&& y2
<= b
);
168 return (l
< x1
+ (draggable
.helperProportions
.width
/ 2) // Right Half
169 && x2
- (draggable
.helperProportions
.width
/ 2) < r
// Left Half
170 && t
< y1
+ (draggable
.helperProportions
.height
/ 2) // Bottom Half
171 && y2
- (draggable
.helperProportions
.height
/ 2) < b
); // Top Half
174 var draggableLeft
= ((draggable
.positionAbs
|| draggable
.position
.absolute
).left
+ (draggable
.clickOffset
|| draggable
.offset
.click
).left
),
175 draggableTop
= ((draggable
.positionAbs
|| draggable
.position
.absolute
).top
+ (draggable
.clickOffset
|| draggable
.offset
.click
).top
),
176 isOver
= $.ui
.isOver(draggableTop
, draggableLeft
, t
, l
, droppable
.proportions
.height
, droppable
.proportions
.width
);
181 (y1
>= t
&& y1
<= b
) || // Top edge touching
182 (y2
>= t
&& y2
<= b
) || // Bottom edge touching
183 (y1
< t
&& y2
> b
) // Surrounded vertically
185 (x1
>= l
&& x1
<= r
) || // Left edge touching
186 (x2
>= l
&& x2
<= r
) || // Right edge touching
187 (x1
< l
&& x2
> r
) // Surrounded horizontally
198 This manager tracks offsets of draggables and droppables
202 droppables
: { 'default': [] },
203 prepareOffsets: function(t
, event
) {
205 var m
= $.ui
.ddmanager
.droppables
[t
.options
.scope
] || [];
206 var type
= event
? event
.type
: null; // workaround for #2317
207 var list
= (t
.currentItem
|| t
.element
).find(":data(droppable)").andSelf();
209 droppablesLoop
: for (var i
= 0; i
< m
.length
; i
++) {
211 if(m
[i
].options
.disabled
|| (t
&& !m
[i
].accept
.call(m
[i
].element
[0],(t
.currentItem
|| t
.element
)))) continue; //No disabled and non-accepted
212 for (var j
=0; j
< list
.length
; j
++) { if(list
[j
] == m
[i
].element
[0]) { m
[i
].proportions
.height
= 0; continue droppablesLoop
; } }; //Filter out elements in the current dragged item
213 m
[i
].visible
= m
[i
].element
.css("display") != "none"; if(!m
[i
].visible
) continue; //If the element is not visible, continue
215 if(type
== "mousedown") m
[i
]._activate
.call(m
[i
], event
); //Activate the droppable if used directly from draggables
217 m
[i
].offset
= m
[i
].element
.offset();
218 m
[i
].proportions
= { width
: m
[i
].element
[0].offsetWidth
, height
: m
[i
].element
[0].offsetHeight
};
223 drop: function(draggable
, event
) {
226 $.each($.ui
.ddmanager
.droppables
[draggable
.options
.scope
] || [], function() {
228 if(!this.options
) return;
229 if (!this.options
.disabled
&& this.visible
&& $.ui
.intersect(draggable
, this, this.options
.tolerance
))
230 dropped
= this._drop
.call(this, event
) || dropped
;
232 if (!this.options
.disabled
&& this.visible
&& this.accept
.call(this.element
[0],(draggable
.currentItem
|| draggable
.element
))) {
233 this.isout
= 1; this.isover
= 0;
234 this._deactivate
.call(this, event
);
241 dragStart: function( draggable
, event
) {
242 //Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003)
243 draggable
.element
.parents( ":not(body,html)" ).bind( "scroll.droppable", function() {
244 if( !draggable
.options
.refreshPositions
) $.ui
.ddmanager
.prepareOffsets( draggable
, event
);
247 drag: function(draggable
, event
) {
249 //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
250 if(draggable
.options
.refreshPositions
) $.ui
.ddmanager
.prepareOffsets(draggable
, event
);
252 //Run through all droppables and check their positions based on specific tolerance options
253 $.each($.ui
.ddmanager
.droppables
[draggable
.options
.scope
] || [], function() {
255 if(this.options
.disabled
|| this.greedyChild
|| !this.visible
) return;
256 var intersects
= $.ui
.intersect(draggable
, this, this.options
.tolerance
);
258 var c
= !intersects
&& this.isover
== 1 ? 'isout' : (intersects
&& this.isover
== 0 ? 'isover' : null);
262 if (this.options
.greedy
) {
263 // find droppable parents with same scope
264 var scope
= this.options
.scope
;
265 var parent
= this.element
.parents(':data(droppable)').filter(function () {
266 return $.data(this, 'droppable').options
.scope
=== scope
;
270 parentInstance
= $.data(parent
[0], 'droppable');
271 parentInstance
.greedyChild
= (c
== 'isover' ? 1 : 0);
275 // we just moved into a greedy child
276 if (parentInstance
&& c
== 'isover') {
277 parentInstance
['isover'] = 0;
278 parentInstance
['isout'] = 1;
279 parentInstance
._out
.call(parentInstance
, event
);
282 this[c
] = 1; this[c
== 'isout' ? 'isover' : 'isout'] = 0;
283 this[c
== "isover" ? "_over" : "_out"].call(this, event
);
285 // we just moved out of a greedy child
286 if (parentInstance
&& c
== 'isout') {
287 parentInstance
['isout'] = 0;
288 parentInstance
['isover'] = 1;
289 parentInstance
._over
.call(parentInstance
, event
);
294 dragStop: function( draggable
, event
) {
295 draggable
.element
.parents( ":not(body,html)" ).unbind( "scroll.droppable" );
296 //Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003)
297 if( !draggable
.options
.refreshPositions
) $.ui
.ddmanager
.prepareOffsets( draggable
, event
);