drag and drop - based Prototype and imitate script.aculo.us dragdrop.js
DragController = { drags: [], dragging: false, currentDrag: null, register: function(drag) { if (this.drags.length == 0) { Event.observe(document, "mouseup", this.endDrag.bindAsEventListener(this)); Event.observe(document, "mousemove", this.updateDrag.bindAsEventListener(this)); Event.observe(document, "keypress", this.keyPress.bindAsEventListener(this)); } this.drags.push(drag); }, updateDrag: function(event) { this.currentDrag && this.currentDrag.updateDrag(event); }, endDrag: function(event) { this.currentDrag && this.currentDrag.endDrag(event, true); }, keyPress: function(event) { this.currentDrag && this.currentDrag.keyPress(event); }};Drag = Class.create({ initialize: function(element) { var defaults = { handle: false, zindex: 1000, revert: false, ghosting: false, opacity: 0.0 }; this.element = $(element); this.options = Object.extend(defaults, arguments[1] || {}); DragController.register(element); // fix IE position problem. if (Prototype.Browser.IE) { var position = this.element.style.position; if (position == 'static' || !position) this.element.style.position = 'relative'; } Event.observe(element, "mousedown", this.startDrag.bindAsEventListener(this)); }, startDrag: function(event) { if (Event.isLeftClick(event)) { this.relativePosition = [this.element.style.left, this.element.style.top]; this.clone = this.element.cloneNode(true); this.positionAbsolutize(); this.element.parentNode.insertBefore(this.clone, this.element); this.originalOpacity = this.element.getOpacity(); this.element.setOpacity(0.7); if (!this.options.ghosting) { this.clone.setOpacity(this.options.opacity); } this.element.style.zIndex = this.options.zindex; this.element.style.cursor = "move"; // hack safari inline element shadow problem. // this negative effect is block-level element display inline if (Prototype.Browser.WebKit && this.element.style.display != "block" && ["a", "b", "i", "q", "s", "em", "big", "sup", "sub", "abbr", "code", "cite", "span", "quote", "small", "strike", "strong"].include(this.element.tagName.toLowerCase())) this.element.style.display = "inline-block"; this.startPointer = [Event.pointerX(event), Event.pointerY(event)]; this.positionedOffset = [this.element.offsetLeft, this.element.offsetTop]; DragController.dragging = true; DragController.currentDrag = this; } Event.stop(event); }, updateDrag: function(event) { if (DragController.dragging) { var currentPointer = [Event.pointerX(event), Event.pointerY(event)]; this.element.style.left = (currentPointer[0] - this.startPointer[0] + this.positionedOffset[0] - parseInt(this.element.style.marginLeft || 0)) + "px"; this.element.style.top = (currentPointer[1] - this.startPointer[1] + this.positionedOffset[1] - parseInt(this.element.style.marginTop || 0)) + "px"; Drop.show(currentPointer, this.element); } Event.stop(event); }, endDrag: function(event, success) { if (DragController.dragging) { DragController.dragging = false; DragController.currentDrag = null; this.element.setOpacity(this.originalOpacity); var currentPointer = [Event.pointerX(event), Event.pointerY(event)]; this.element.style.position = "relative"; this.element.style.left = (currentPointer[0] - this.startPointer[0] + parseInt(this.relativePosition[0] || 0)) + "px"; this.element.style.top = (currentPointer[1] - this.startPointer[1] + parseInt(this.relativePosition[1] || 0)) + "px"; this.clone.remove(); // clone remove must before Drop event fire because clone will hold position this.clone = null; if (!success) { this.revertDrag(event); } else { var dropped; if (Drop.lastDrop) { Drop.removeHoverClass(); dropped = Drop.fire(event, this.element, Drop.lastDrop); } if (!dropped && this.options.revert) this.revertDrag(event); } } Event.stop(event); }, keyPress: function(event) { if (event.keyCode != Event.KEY_ESC) return; this.endDrag(event, false); Event.stop(event); }, revertDrag: function(event) { this.element.style.left = this.relativePosition[0]; this.element.style.top = this.relativePosition[1]; }, positionAbsolutize: function() { if (this.element.getStyle('position') == 'absolute') return; var offsets = [this.element.offsetLeft, this.element.offsetTop]; // offsetLeft include this element's marginLeft value. var left = offsets[0] - parseInt(this.element.style.marginLeft || 0); var top = offsets[1] - parseInt(this.element.style.marginTop || 0); this.element.style.position = 'absolute'; this.element.style.top = top + 'px'; this.element.style.left = left + 'px'; }});var Drop = { drops: [], lastDrop: null, add: function(element) { var drop = Object.extend({ hoverClass: null }, arguments[1] || {}); drop.element = $(element); this.drops.push(drop); }, isContained: function(drag, drop) { var container = drag.parentNode; return drop.containers.detect(function(c) { return $(c) == container }); }, dragHovered: function(pointer, drag, drop) { return ((drop.element != drag) && ((!drop.containers) || this.isContained(drag, drop)) && Position.within(drop.element, pointer[0], pointer[1])); }, removeHoverClass: function() { Element.removeClassName(Drop.lastDrop.element, Drop.lastDrop.hoverclass); }, show: function(pointer, drag) { if (!this.drops.length) return; var hovered = false; this.drops.each(function(drop) { if (Drop.dragHovered(pointer, drag, drop)) { hovered = true; Drop.lastDrop = drop; Element.addClassName(drop.element, drop.hoverclass); if (drop.onHover) drop.onHover(drag, drop.element); } }); if (Drop.lastDrop && !hovered) this.removeHoverClass(); }, fire: function(event, drag, drop) { if (drop && this.dragHovered([Event.pointerX(event), Event.pointerY(event)], drag, drop)) { if (drop.onDrop) drop.onDrop(drag, drop.element, event); return true; } }} |