233 lines
6.9 KiB
JavaScript
233 lines
6.9 KiB
JavaScript
af_DragNDrop = function() {
|
|
|
|
var that = this;
|
|
|
|
// offset inside clicked element
|
|
that.mouseOffset = {};
|
|
// all drop targets
|
|
that.dropTargets = {};
|
|
|
|
// container which is actually being moved around
|
|
that.dragContainer = null;
|
|
// element that is currently being dragged
|
|
that.currentlyDragging = null;
|
|
// drag-Id
|
|
that.currentId = '';
|
|
// dragging already initialized?
|
|
that.draggingInitialized = false;
|
|
// position, where we started dragging
|
|
that.startPosition = {};
|
|
|
|
that.dragRegex = /\bdrag_(.*?)\b/;
|
|
that.dropRegex = /\bdrop_(.*?)\b/;
|
|
// @TODO: maybe this can be replaced by manually setting the regex.global flag?
|
|
that.dropRegexG = /\bdrop_(.*?)\b/g;
|
|
|
|
that.load = function() {
|
|
|
|
// create drag container
|
|
that.dragContainer = document.createElement('div');
|
|
that.dragContainer.className = 'dragcontainer';
|
|
// better solution for this?
|
|
document.getElementsByTagName('body')[0].appendChild(that.dragContainer);
|
|
|
|
// find draggable elements
|
|
var elements = af_CSS.getElementsByClass(that.dragRegex);
|
|
for (var i = 0; i < elements.length; ++i) {
|
|
af_Events.addEventListener(elements[i], 'mousedown', that.startDrag);
|
|
af_Events.addEventListener(elements[i], 'click', that.interceptClick);
|
|
// af_Events.addEventListener(elements[i], 'click', function(event) {alert('Clicked!'); });
|
|
}
|
|
|
|
// find drop targets
|
|
var elements = af_CSS.getElementsByClass(that.dropRegex);
|
|
var match;
|
|
for (var i = 0; i < elements.length; ++i) {
|
|
// an elment can serve as a drop target for differend IDs
|
|
while (match = that.dropRegexG.exec(elements[i].className)) {
|
|
var id = match[1];
|
|
that.dropTargets[id] = that.dropTargets[id] || new Array();
|
|
that.dropTargets[id].push(elements[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
that.startDrag = function(event) {
|
|
event = event || window.event;
|
|
|
|
var mpos = af_Events.getMousePosition(event);
|
|
var epos = af_CSS.getPosition(this);
|
|
|
|
// record mouse offset
|
|
that.mouseOffset = {
|
|
x: mpos.x - epos.x,
|
|
y: mpos.y - epos.y
|
|
}
|
|
|
|
that.startPosition = mpos;
|
|
that.currentlyDragging = this;
|
|
that.draggingInitialized = false;
|
|
|
|
af_Events.stopEvent(event);
|
|
return false;
|
|
}
|
|
|
|
that.initDrag = function(event) {
|
|
|
|
// find drag id
|
|
var match = that.dragRegex.exec(that.currentlyDragging.className);
|
|
if (!match || !match[1]) {
|
|
return false;
|
|
}
|
|
that.currentId = match[1];
|
|
|
|
// are there any drop targets?
|
|
if (!that.dropTargets[that.currentId]) {
|
|
return false;
|
|
}
|
|
|
|
// highlight drop targets
|
|
for (var i = 0; i < that.dropTargets[that.currentId].length; ++i) {
|
|
af_CSS.addClass(that.dropTargets[that.currentId][i], 'active_' + that.currentId);
|
|
}
|
|
|
|
var mpos = af_Events.getMousePosition(event);
|
|
|
|
// prepare drag container
|
|
that.dragContainer.innerHTML = '';
|
|
that.dragContainer.style.top = mpos.y - that.mouseOffset.y + 'px';
|
|
that.dragContainer.style.left = mpos.x - that.mouseOffset.x + 'px';
|
|
// copy element into drag container
|
|
var clone = that.currentlyDragging.cloneNode(true)
|
|
var dims = af_CSS.getDimensions(that.currentlyDragging);
|
|
clone.style.width = dims.width + 'px';
|
|
clone.style.height = dims.height + 'px';
|
|
that.dragContainer.appendChild(clone);
|
|
that.dragContainer.style.display = 'block';
|
|
// mark element as being dragged
|
|
af_CSS.addClass(that.currentlyDragging, 'dragging');
|
|
that.draggingInitialized = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
that.runDrag = function(event) {
|
|
if (!that.currentlyDragging) {
|
|
return;
|
|
}
|
|
event = event || window.event;
|
|
|
|
if (!that.draggingInitialized) {
|
|
// first mouse move, set up dragging
|
|
if (!that.initDrag(event)) {
|
|
af_Events.stopEvent(event);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
var mpos = af_Events.getMousePosition(event);
|
|
|
|
// move drag container
|
|
that.dragContainer.style.left = (mpos.x - that.mouseOffset.x) + 'px';
|
|
that.dragContainer.style.top = (mpos.y - that.mouseOffset.y) + 'px';
|
|
|
|
var dropTarget = null;
|
|
for (var i = 0; i < that.dropTargets[that.currentId].length; ++i) {
|
|
if (
|
|
that.dropTargets[that.currentId][i] != that.currentlyDragging &&
|
|
that.testBoundingBox(that.getBoundingBox(that.dropTargets[that.currentId][i]), mpos)
|
|
) {
|
|
af_CSS.addClass(that.dropTargets[that.currentId][i], 'hover_' + that.currentId);
|
|
} else {
|
|
af_CSS.removeClass(that.dropTargets[that.currentId][i], 'hover_' + that.currentId);
|
|
}
|
|
}
|
|
|
|
// required for Internet Explorer:
|
|
return false;
|
|
}
|
|
|
|
that.endDrag = function(event) {
|
|
if (!that.draggingInitialized) {
|
|
that.currentlyDragging = null;
|
|
}
|
|
if (!that.currentlyDragging) {
|
|
return;
|
|
}
|
|
event = event || window.event;
|
|
|
|
// find drop target
|
|
if (!that.dropTargets[that.currentId]) {
|
|
return;
|
|
}
|
|
var dropTarget = null;
|
|
var mpos = af_Events.getMousePosition(event);
|
|
for (var i = 0; i < that.dropTargets[that.currentId].length; ++i) {
|
|
if (that.testBoundingBox(that.getBoundingBox(that.dropTargets[that.currentId][i]), mpos)) {
|
|
dropTarget = that.dropTargets[that.currentId][i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
// reset highlighted drop targets
|
|
for (var i = 0; i < that.dropTargets[that.currentId].length; ++i) {
|
|
af_CSS.removeClass(that.dropTargets[that.currentId][i], 'active_' + that.currentId);
|
|
af_CSS.removeClass(that.dropTargets[that.currentId][i], 'hover_' + that.currentId);
|
|
}
|
|
|
|
// backup element
|
|
var element = that.currentlyDragging;
|
|
|
|
// stop dragging
|
|
af_CSS.removeClass(that.currentlyDragging, 'dragging');
|
|
that.currentlyDragging = null;
|
|
that.dragContainer.style.display = 'none';
|
|
that.dragContainer.style.top = 0;
|
|
that.dragContainer.style.left = 0;
|
|
that.dragContainer.innerHTML = '';
|
|
|
|
af_Events.stopEvent(event);
|
|
|
|
if (dropTarget && that['drop' + that.currentId]) {
|
|
return that['drop' + that.currentId](element, dropTarget);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// intercepts clicks if mouse has moved
|
|
that.interceptClick = function(event) {
|
|
event = event || window.event;
|
|
var mpos = af_Events.getMousePosition(event);
|
|
if (mpos.x != that.startPosition.x || mpos.y != that.startPosition.y) {
|
|
// mouse was moved => dragging took place => intercept click
|
|
af_Events.stopEvent(event);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
that.getBoundingBox = function(element) {
|
|
var coords = af_CSS.getPosition(element);
|
|
var dimensions = af_CSS.getDimensions(element);
|
|
return {
|
|
xMin: coords.x,
|
|
yMin: coords.y,
|
|
xMax: coords.x + dimensions.width,
|
|
yMax: coords.y + dimensions.height
|
|
}
|
|
}
|
|
|
|
that.testBoundingBox = function(bbox, mpos) {
|
|
return (
|
|
mpos.x > bbox.xMin &&
|
|
mpos.x < bbox.xMax &&
|
|
mpos.y > bbox.yMin &&
|
|
mpos.y < bbox.yMax
|
|
);
|
|
}
|
|
|
|
af_Events.addOnEvent(window, 'load', that.load);
|
|
af_Events.addEventListener(document, 'mousemove', that.runDrag);
|
|
af_Events.addEventListener(document, 'mouseup', that.endDrag);
|
|
} |