mirror of
https://github.com/jquery/jquery-ui.git
synced 2024-11-21 11:04:24 +00:00
37dcc3e21d
For instance, this is useful for the jquery-ui-rails gem, which does not use jQuery UI's own minification, but relies on Rails to minify the files where necessary. Rails in turn uses UglifyJS for JS and YUI for CSS, both of which respect the /*! ... */ convention.
294 lines
9.9 KiB
JavaScript
294 lines
9.9 KiB
JavaScript
/*!
|
|
* jQuery UI Droppable @VERSION
|
|
*
|
|
* Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
|
|
* Dual licensed under the MIT or GPL Version 2 licenses.
|
|
* http://jquery.org/license
|
|
*
|
|
* http://docs.jquery.com/UI/Droppables
|
|
*
|
|
* Depends:
|
|
* jquery.ui.core.js
|
|
* jquery.ui.widget.js
|
|
* jquery.ui.mouse.js
|
|
* jquery.ui.draggable.js
|
|
*/
|
|
(function( $, undefined ) {
|
|
|
|
$.widget("ui.droppable", {
|
|
version: "@VERSION",
|
|
widgetEventPrefix: "drop",
|
|
options: {
|
|
accept: '*',
|
|
activeClass: false,
|
|
addClasses: true,
|
|
greedy: false,
|
|
hoverClass: false,
|
|
scope: 'default',
|
|
tolerance: 'intersect'
|
|
},
|
|
_create: function() {
|
|
|
|
var o = this.options, accept = o.accept;
|
|
this.isover = 0; this.isout = 1;
|
|
|
|
this.accept = $.isFunction(accept) ? accept : function(d) {
|
|
return d.is(accept);
|
|
};
|
|
|
|
//Store the droppable's proportions
|
|
this.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight };
|
|
|
|
// Add the reference and positions to the manager
|
|
$.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || [];
|
|
$.ui.ddmanager.droppables[o.scope].push(this);
|
|
|
|
(o.addClasses && this.element.addClass("ui-droppable"));
|
|
|
|
},
|
|
|
|
destroy: function() {
|
|
var drop = $.ui.ddmanager.droppables[this.options.scope];
|
|
for ( var i = 0; i < drop.length; i++ )
|
|
if ( drop[i] == this )
|
|
drop.splice(i, 1);
|
|
|
|
this.element
|
|
.removeClass("ui-droppable ui-droppable-disabled")
|
|
.removeData("droppable")
|
|
.unbind(".droppable");
|
|
|
|
return this;
|
|
},
|
|
|
|
_setOption: function(key, value) {
|
|
|
|
if(key == 'accept') {
|
|
this.accept = $.isFunction(value) ? value : function(d) {
|
|
return d.is(value);
|
|
};
|
|
}
|
|
$.Widget.prototype._setOption.apply(this, arguments);
|
|
},
|
|
|
|
_activate: function(event) {
|
|
var draggable = $.ui.ddmanager.current;
|
|
if(this.options.activeClass) this.element.addClass(this.options.activeClass);
|
|
(draggable && this._trigger('activate', event, this.ui(draggable)));
|
|
},
|
|
|
|
_deactivate: function(event) {
|
|
var draggable = $.ui.ddmanager.current;
|
|
if(this.options.activeClass) this.element.removeClass(this.options.activeClass);
|
|
(draggable && this._trigger('deactivate', event, this.ui(draggable)));
|
|
},
|
|
|
|
_over: function(event) {
|
|
|
|
var draggable = $.ui.ddmanager.current;
|
|
if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element
|
|
|
|
if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
|
|
if(this.options.hoverClass) this.element.addClass(this.options.hoverClass);
|
|
this._trigger('over', event, this.ui(draggable));
|
|
}
|
|
|
|
},
|
|
|
|
_out: function(event) {
|
|
|
|
var draggable = $.ui.ddmanager.current;
|
|
if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element
|
|
|
|
if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
|
|
if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass);
|
|
this._trigger('out', event, this.ui(draggable));
|
|
}
|
|
|
|
},
|
|
|
|
_drop: function(event,custom) {
|
|
|
|
var draggable = custom || $.ui.ddmanager.current;
|
|
if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return false; // Bail if draggable and droppable are same element
|
|
|
|
var childrenIntersection = false;
|
|
this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function() {
|
|
var inst = $.data(this, 'droppable');
|
|
if(
|
|
inst.options.greedy
|
|
&& !inst.options.disabled
|
|
&& inst.options.scope == draggable.options.scope
|
|
&& inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element))
|
|
&& $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance)
|
|
) { childrenIntersection = true; return false; }
|
|
});
|
|
if(childrenIntersection) return false;
|
|
|
|
if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
|
|
if(this.options.activeClass) this.element.removeClass(this.options.activeClass);
|
|
if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass);
|
|
this._trigger('drop', event, this.ui(draggable));
|
|
return this.element;
|
|
}
|
|
|
|
return false;
|
|
|
|
},
|
|
|
|
ui: function(c) {
|
|
return {
|
|
draggable: (c.currentItem || c.element),
|
|
helper: c.helper,
|
|
position: c.position,
|
|
offset: c.positionAbs
|
|
};
|
|
}
|
|
|
|
});
|
|
|
|
$.ui.intersect = function(draggable, droppable, toleranceMode) {
|
|
|
|
if (!droppable.offset) return false;
|
|
|
|
var x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width,
|
|
y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height;
|
|
var l = droppable.offset.left, r = l + droppable.proportions.width,
|
|
t = droppable.offset.top, b = t + droppable.proportions.height;
|
|
|
|
switch (toleranceMode) {
|
|
case 'fit':
|
|
return (l <= x1 && x2 <= r
|
|
&& t <= y1 && y2 <= b);
|
|
break;
|
|
case 'intersect':
|
|
return (l < x1 + (draggable.helperProportions.width / 2) // Right Half
|
|
&& x2 - (draggable.helperProportions.width / 2) < r // Left Half
|
|
&& t < y1 + (draggable.helperProportions.height / 2) // Bottom Half
|
|
&& y2 - (draggable.helperProportions.height / 2) < b ); // Top Half
|
|
break;
|
|
case 'pointer':
|
|
var draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left),
|
|
draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top),
|
|
isOver = $.ui.isOver(draggableTop, draggableLeft, t, l, droppable.proportions.height, droppable.proportions.width);
|
|
return isOver;
|
|
break;
|
|
case 'touch':
|
|
return (
|
|
(y1 >= t && y1 <= b) || // Top edge touching
|
|
(y2 >= t && y2 <= b) || // Bottom edge touching
|
|
(y1 < t && y2 > b) // Surrounded vertically
|
|
) && (
|
|
(x1 >= l && x1 <= r) || // Left edge touching
|
|
(x2 >= l && x2 <= r) || // Right edge touching
|
|
(x1 < l && x2 > r) // Surrounded horizontally
|
|
);
|
|
break;
|
|
default:
|
|
return false;
|
|
break;
|
|
}
|
|
|
|
};
|
|
|
|
/*
|
|
This manager tracks offsets of draggables and droppables
|
|
*/
|
|
$.ui.ddmanager = {
|
|
current: null,
|
|
droppables: { 'default': [] },
|
|
prepareOffsets: function(t, event) {
|
|
|
|
var m = $.ui.ddmanager.droppables[t.options.scope] || [];
|
|
var type = event ? event.type : null; // workaround for #2317
|
|
var list = (t.currentItem || t.element).find(":data(droppable)").andSelf();
|
|
|
|
droppablesLoop: for (var i = 0; i < m.length; i++) {
|
|
|
|
if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) continue; //No disabled and non-accepted
|
|
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
|
|
m[i].visible = m[i].element.css("display") != "none"; if(!m[i].visible) continue; //If the element is not visible, continue
|
|
|
|
if(type == "mousedown") m[i]._activate.call(m[i], event); //Activate the droppable if used directly from draggables
|
|
|
|
m[i].offset = m[i].element.offset();
|
|
m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight };
|
|
|
|
}
|
|
|
|
},
|
|
drop: function(draggable, event) {
|
|
|
|
var dropped = false;
|
|
$.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {
|
|
|
|
if(!this.options) return;
|
|
if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance))
|
|
dropped = this._drop.call(this, event) || dropped;
|
|
|
|
if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
|
|
this.isout = 1; this.isover = 0;
|
|
this._deactivate.call(this, event);
|
|
}
|
|
|
|
});
|
|
return dropped;
|
|
|
|
},
|
|
dragStart: function( draggable, event ) {
|
|
//Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003)
|
|
draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() {
|
|
if( !draggable.options.refreshPositions ) $.ui.ddmanager.prepareOffsets( draggable, event );
|
|
});
|
|
},
|
|
drag: function(draggable, event) {
|
|
|
|
//If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
|
|
if(draggable.options.refreshPositions) $.ui.ddmanager.prepareOffsets(draggable, event);
|
|
|
|
//Run through all droppables and check their positions based on specific tolerance options
|
|
$.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {
|
|
|
|
if(this.options.disabled || this.greedyChild || !this.visible) return;
|
|
var intersects = $.ui.intersect(draggable, this, this.options.tolerance);
|
|
|
|
var c = !intersects && this.isover == 1 ? 'isout' : (intersects && this.isover == 0 ? 'isover' : null);
|
|
if(!c) return;
|
|
|
|
var parentInstance;
|
|
if (this.options.greedy) {
|
|
var parent = this.element.parents(':data(droppable):eq(0)');
|
|
if (parent.length) {
|
|
parentInstance = $.data(parent[0], 'droppable');
|
|
parentInstance.greedyChild = (c == 'isover' ? 1 : 0);
|
|
}
|
|
}
|
|
|
|
// we just moved into a greedy child
|
|
if (parentInstance && c == 'isover') {
|
|
parentInstance['isover'] = 0;
|
|
parentInstance['isout'] = 1;
|
|
parentInstance._out.call(parentInstance, event);
|
|
}
|
|
|
|
this[c] = 1; this[c == 'isout' ? 'isover' : 'isout'] = 0;
|
|
this[c == "isover" ? "_over" : "_out"].call(this, event);
|
|
|
|
// we just moved out of a greedy child
|
|
if (parentInstance && c == 'isout') {
|
|
parentInstance['isout'] = 0;
|
|
parentInstance['isover'] = 1;
|
|
parentInstance._over.call(parentInstance, event);
|
|
}
|
|
});
|
|
|
|
},
|
|
dragStop: function( draggable, event ) {
|
|
draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" );
|
|
//Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003)
|
|
if( !draggable.options.refreshPositions ) $.ui.ddmanager.prepareOffsets( draggable, event );
|
|
}
|
|
};
|
|
|
|
})(jQuery);
|