2 * jQuery UI Droppable 1.9.2
5 * Copyright 2012 jQuery Foundation and other contributors
6 * Released under the MIT license.
7 * http://jquery.org/license
9 * http://api.jqueryui.com/droppable/
15 * jquery.ui.draggable.js
17 (function( $, undefined ) {
19 $.widget("ui.droppable", {
21 widgetEventPrefix
: "drop",
29 tolerance
: 'intersect'
33 var o
= this.options
, accept
= o
.accept
;
34 this.isover
= 0; this.isout
= 1;
36 this.accept
= $.isFunction(accept
) ? accept : function(d
) {
40 //Store the droppable's proportions
41 this.proportions
= { width
: this.element
[0].offsetWidth
, height
: this.element
[0].offsetHeight
};
43 // Add the reference and positions to the manager
44 $.ui
.ddmanager
.droppables
[o
.scope
] = $.ui
.ddmanager
.droppables
[o
.scope
] || [];
45 $.ui
.ddmanager
.droppables
[o
.scope
].push(this);
47 (o
.addClasses
&& this.element
.addClass("ui-droppable"));
51 _destroy: function() {
52 var drop
= $.ui
.ddmanager
.droppables
[this.options
.scope
];
53 for ( var i
= 0; i
< drop
.length
; i
++ )
54 if ( drop
[i
] == this )
57 this.element
.removeClass("ui-droppable ui-droppable-disabled");
60 _setOption: function(key
, value
) {
63 this.accept
= $.isFunction(value
) ? value : function(d
) {
67 $.Widget
.prototype._setOption
.apply(this, arguments
);
70 _activate: function(event
) {
71 var draggable
= $.ui
.ddmanager
.current
;
72 if(this.options
.activeClass
) this.element
.addClass(this.options
.activeClass
);
73 (draggable
&& this._trigger('activate', event
, this.ui(draggable
)));
76 _deactivate: function(event
) {
77 var draggable
= $.ui
.ddmanager
.current
;
78 if(this.options
.activeClass
) this.element
.removeClass(this.options
.activeClass
);
79 (draggable
&& this._trigger('deactivate', event
, this.ui(draggable
)));
82 _over: function(event
) {
84 var draggable
= $.ui
.ddmanager
.current
;
85 if (!draggable
|| (draggable
.currentItem
|| draggable
.element
)[0] == this.element
[0]) return; // Bail if draggable and droppable are same element
87 if (this.accept
.call(this.element
[0],(draggable
.currentItem
|| draggable
.element
))) {
88 if(this.options
.hoverClass
) this.element
.addClass(this.options
.hoverClass
);
89 this._trigger('over', event
, this.ui(draggable
));
94 _out: function(event
) {
96 var draggable
= $.ui
.ddmanager
.current
;
97 if (!draggable
|| (draggable
.currentItem
|| draggable
.element
)[0] == this.element
[0]) return; // Bail if draggable and droppable are same element
99 if (this.accept
.call(this.element
[0],(draggable
.currentItem
|| draggable
.element
))) {
100 if(this.options
.hoverClass
) this.element
.removeClass(this.options
.hoverClass
);
101 this._trigger('out', event
, this.ui(draggable
));
106 _drop: function(event
,custom
) {
108 var draggable
= custom
|| $.ui
.ddmanager
.current
;
109 if (!draggable
|| (draggable
.currentItem
|| draggable
.element
)[0] == this.element
[0]) return false; // Bail if draggable and droppable are same element
111 var childrenIntersection
= false;
112 this.element
.find(":data(droppable)").not(".ui-draggable-dragging").each(function() {
113 var inst
= $.data(this, 'droppable');
116 && !inst
.options
.disabled
117 && inst
.options
.scope
== draggable
.options
.scope
118 && inst
.accept
.call(inst
.element
[0], (draggable
.currentItem
|| draggable
.element
))
119 && $.ui
.intersect(draggable
, $.extend(inst
, { offset
: inst
.element
.offset() }), inst
.options
.tolerance
)
120 ) { childrenIntersection
= true; return false; }
122 if(childrenIntersection
) return false;
124 if(this.accept
.call(this.element
[0],(draggable
.currentItem
|| draggable
.element
))) {
125 if(this.options
.activeClass
) this.element
.removeClass(this.options
.activeClass
);
126 if(this.options
.hoverClass
) this.element
.removeClass(this.options
.hoverClass
);
127 this._trigger('drop', event
, this.ui(draggable
));
137 draggable
: (c
.currentItem
|| c
.element
),
139 position
: c
.position
,
140 offset
: c
.positionAbs
146 $.ui
.intersect = function(draggable
, droppable
, toleranceMode
) {
148 if (!droppable
.offset
) return false;
150 var x1
= (draggable
.positionAbs
|| draggable
.position
.absolute
).left
, x2
= x1
+ draggable
.helperProportions
.width
,
151 y1
= (draggable
.positionAbs
|| draggable
.position
.absolute
).top
, y2
= y1
+ draggable
.helperProportions
.height
;
152 var l
= droppable
.offset
.left
, r
= l
+ droppable
.proportions
.width
,
153 t
= droppable
.offset
.top
, b
= t
+ droppable
.proportions
.height
;
155 switch (toleranceMode
) {
157 return (l
<= x1
&& x2
<= r
158 && t
<= y1
&& y2
<= b
);
161 return (l
< x1
+ (draggable
.helperProportions
.width
/ 2) // Right Half
162 && x2
- (draggable
.helperProportions
.width
/ 2) < r
// Left Half
163 && t
< y1
+ (draggable
.helperProportions
.height
/ 2) // Bottom Half
164 && y2
- (draggable
.helperProportions
.height
/ 2) < b
); // Top Half
167 var draggableLeft
= ((draggable
.positionAbs
|| draggable
.position
.absolute
).left
+ (draggable
.clickOffset
|| draggable
.offset
.click
).left
),
168 draggableTop
= ((draggable
.positionAbs
|| draggable
.position
.absolute
).top
+ (draggable
.clickOffset
|| draggable
.offset
.click
).top
),
169 isOver
= $.ui
.isOver(draggableTop
, draggableLeft
, t
, l
, droppable
.proportions
.height
, droppable
.proportions
.width
);
174 (y1
>= t
&& y1
<= b
) || // Top edge touching
175 (y2
>= t
&& y2
<= b
) || // Bottom edge touching
176 (y1
< t
&& y2
> b
) // Surrounded vertically
178 (x1
>= l
&& x1
<= r
) || // Left edge touching
179 (x2
>= l
&& x2
<= r
) || // Right edge touching
180 (x1
< l
&& x2
> r
) // Surrounded horizontally
191 This manager tracks offsets of draggables and droppables
195 droppables
: { 'default': [] },
196 prepareOffsets: function(t
, event
) {
198 var m
= $.ui
.ddmanager
.droppables
[t
.options
.scope
] || [];
199 var type
= event
? event
.type
: null; // workaround for #2317
200 var list
= (t
.currentItem
|| t
.element
).find(":data(droppable)").andSelf();
202 droppablesLoop
: for (var i
= 0; i
< m
.length
; i
++) {
204 if(m
[i
].options
.disabled
|| (t
&& !m
[i
].accept
.call(m
[i
].element
[0],(t
.currentItem
|| t
.element
)))) continue; //No disabled and non-accepted
205 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
206 m
[i
].visible
= m
[i
].element
.css("display") != "none"; if(!m
[i
].visible
) continue; //If the element is not visible, continue
208 if(type
== "mousedown") m
[i
]._activate
.call(m
[i
], event
); //Activate the droppable if used directly from draggables
210 m
[i
].offset
= m
[i
].element
.offset();
211 m
[i
].proportions
= { width
: m
[i
].element
[0].offsetWidth
, height
: m
[i
].element
[0].offsetHeight
};
216 drop: function(draggable
, event
) {
219 $.each($.ui
.ddmanager
.droppables
[draggable
.options
.scope
] || [], function() {
221 if(!this.options
) return;
222 if (!this.options
.disabled
&& this.visible
&& $.ui
.intersect(draggable
, this, this.options
.tolerance
))
223 dropped
= this._drop
.call(this, event
) || dropped
;
225 if (!this.options
.disabled
&& this.visible
&& this.accept
.call(this.element
[0],(draggable
.currentItem
|| draggable
.element
))) {
226 this.isout
= 1; this.isover
= 0;
227 this._deactivate
.call(this, event
);
234 dragStart: function( draggable
, event
) {
235 //Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003)
236 draggable
.element
.parentsUntil( "body" ).bind( "scroll.droppable", function() {
237 if( !draggable
.options
.refreshPositions
) $.ui
.ddmanager
.prepareOffsets( draggable
, event
);
240 drag: function(draggable
, event
) {
242 //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
243 if(draggable
.options
.refreshPositions
) $.ui
.ddmanager
.prepareOffsets(draggable
, event
);
245 //Run through all droppables and check their positions based on specific tolerance options
246 $.each($.ui
.ddmanager
.droppables
[draggable
.options
.scope
] || [], function() {
248 if(this.options
.disabled
|| this.greedyChild
|| !this.visible
) return;
249 var intersects
= $.ui
.intersect(draggable
, this, this.options
.tolerance
);
251 var c
= !intersects
&& this.isover
== 1 ? 'isout' : (intersects
&& this.isover
== 0 ? 'isover' : null);
255 if (this.options
.greedy
) {
256 // find droppable parents with same scope
257 var scope
= this.options
.scope
;
258 var parent
= this.element
.parents(':data(droppable)').filter(function () {
259 return $.data(this, 'droppable').options
.scope
=== scope
;
263 parentInstance
= $.data(parent
[0], 'droppable');
264 parentInstance
.greedyChild
= (c
== 'isover' ? 1 : 0);
268 // we just moved into a greedy child
269 if (parentInstance
&& c
== 'isover') {
270 parentInstance
['isover'] = 0;
271 parentInstance
['isout'] = 1;
272 parentInstance
._out
.call(parentInstance
, event
);
275 this[c
] = 1; this[c
== 'isout' ? 'isover' : 'isout'] = 0;
276 this[c
== "isover" ? "_over" : "_out"].call(this, event
);
278 // we just moved out of a greedy child
279 if (parentInstance
&& c
== 'isout') {
280 parentInstance
['isout'] = 0;
281 parentInstance
['isover'] = 1;
282 parentInstance
._over
.call(parentInstance
, event
);
287 dragStop: function( draggable
, event
) {
288 draggable
.element
.parentsUntil( "body" ).unbind( "scroll.droppable" );
289 //Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003)
290 if( !draggable
.options
.refreshPositions
) $.ui
.ddmanager
.prepareOffsets( draggable
, event
);