Rollmorad/tools/editor/js/af_DragNDrop.js
2015-11-15 23:18:06 +00:00

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);
}