terom@27: // script.aculo.us dragdrop.js v1.8.0, Tue Nov 06 15:01:40 +0300 2007 terom@27: terom@27: // Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) terom@27: // (c) 2005-2007 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz) terom@27: // terom@27: // script.aculo.us is freely distributable under the terms of an MIT-style license. terom@27: // For details, see the script.aculo.us web site: http://script.aculo.us/ terom@28: // terom@28: // Modified by Tero Marttila to strip unused code terom@27: terom@27: var Draggables = { terom@27: drags: [], terom@27: observers: [], terom@27: terom@27: register: function(draggable) { terom@27: if(this.drags.length == 0) { terom@27: this.eventMouseUp = this.endDrag.bindAsEventListener(this); terom@27: this.eventMouseMove = this.updateDrag.bindAsEventListener(this); terom@27: this.eventKeypress = this.keyPress.bindAsEventListener(this); terom@27: terom@27: Event.observe(document, "mouseup", this.eventMouseUp); terom@27: Event.observe(document, "mousemove", this.eventMouseMove); terom@27: Event.observe(document, "keypress", this.eventKeypress); terom@27: } terom@27: this.drags.push(draggable); terom@27: }, terom@27: terom@27: unregister: function(draggable) { terom@27: this.drags = this.drags.reject(function(d) { return d==draggable }); terom@27: if(this.drags.length == 0) { terom@27: Event.stopObserving(document, "mouseup", this.eventMouseUp); terom@27: Event.stopObserving(document, "mousemove", this.eventMouseMove); terom@27: Event.stopObserving(document, "keypress", this.eventKeypress); terom@27: } terom@27: }, terom@27: terom@27: activate: function(draggable) { terom@27: if(draggable.options.delay) { terom@27: this._timeout = setTimeout(function() { terom@27: Draggables._timeout = null; terom@27: window.focus(); terom@27: Draggables.activeDraggable = draggable; terom@27: }.bind(this), draggable.options.delay); terom@27: } else { terom@27: window.focus(); // allows keypress events if window isn't currently focused, fails for Safari terom@27: this.activeDraggable = draggable; terom@27: } terom@27: }, terom@27: terom@27: deactivate: function() { terom@27: this.activeDraggable = null; terom@27: }, terom@27: terom@27: updateDrag: function(event) { terom@27: if(!this.activeDraggable) return; terom@27: var pointer = [Event.pointerX(event), Event.pointerY(event)]; terom@27: // Mozilla-based browsers fire successive mousemove events with terom@27: // the same coordinates, prevent needless redrawing (moz bug?) terom@27: if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return; terom@27: this._lastPointer = pointer; terom@27: terom@27: this.activeDraggable.updateDrag(event, pointer); terom@27: }, terom@27: terom@27: endDrag: function(event) { terom@27: if(this._timeout) { terom@27: clearTimeout(this._timeout); terom@27: this._timeout = null; terom@27: } terom@27: if(!this.activeDraggable) return; terom@27: this._lastPointer = null; terom@27: this.activeDraggable.endDrag(event); terom@27: this.activeDraggable = null; terom@27: }, terom@27: terom@27: keyPress: function(event) { terom@27: if(this.activeDraggable) terom@27: this.activeDraggable.keyPress(event); terom@27: }, terom@27: terom@27: addObserver: function(observer) { terom@27: this.observers.push(observer); terom@27: this._cacheObserverCallbacks(); terom@27: }, terom@27: terom@27: removeObserver: function(element) { // element instead of observer fixes mem leaks terom@27: this.observers = this.observers.reject( function(o) { return o.element==element }); terom@27: this._cacheObserverCallbacks(); terom@27: }, terom@27: terom@27: notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag' terom@27: if(this[eventName+'Count'] > 0) terom@27: this.observers.each( function(o) { terom@27: if(o[eventName]) o[eventName](eventName, draggable, event); terom@27: }); terom@27: if(draggable.options[eventName]) draggable.options[eventName](draggable, event); terom@27: }, terom@27: terom@27: _cacheObserverCallbacks: function() { terom@27: ['onStart','onEnd','onDrag'].each( function(eventName) { terom@27: Draggables[eventName+'Count'] = Draggables.observers.select( terom@27: function(o) { return o[eventName]; } terom@27: ).length; terom@27: }); terom@27: } terom@27: } terom@27: terom@27: /*--------------------------------------------------------------------------*/ terom@27: terom@27: var Draggable = Class.create({ terom@27: initialize: function(element) { terom@27: var defaults = { terom@27: handle: false, terom@27: zindex: 1000, terom@27: quiet: false, terom@27: delay: 0 terom@27: }; terom@27: terom@27: var options = Object.extend(defaults, arguments[1] || { }); terom@27: terom@27: this.element = $(element); terom@27: terom@27: if(options.handle && Object.isString(options.handle)) terom@27: this.handle = this.element.down('.'+options.handle, 0); terom@27: terom@27: if(!this.handle) this.handle = $(options.handle); terom@27: if(!this.handle) this.handle = this.element; terom@27: terom@27: Element.makePositioned(this.element); // fix IE terom@27: terom@27: this.options = options; terom@27: this.dragging = false; terom@27: terom@27: this.eventMouseDown = this.initDrag.bindAsEventListener(this); terom@27: Event.observe(this.handle, "mousedown", this.eventMouseDown); terom@27: terom@27: Draggables.register(this); terom@27: }, terom@27: terom@27: destroy: function() { terom@27: Event.stopObserving(this.handle, "mousedown", this.eventMouseDown); terom@27: Draggables.unregister(this); terom@27: }, terom@27: terom@27: currentDelta: function() { terom@27: return([ terom@27: parseInt(Element.getStyle(this.element,'left') || '0'), terom@27: parseInt(Element.getStyle(this.element,'top') || '0')]); terom@27: }, terom@27: terom@27: initDrag: function(event) { terom@27: if(!Object.isUndefined(Draggable._dragging[this.element]) && terom@27: Draggable._dragging[this.element]) return; terom@27: if(Event.isLeftClick(event)) { terom@27: // abort on form elements, fixes a Firefox issue terom@27: var src = Event.element(event); terom@27: if((tag_name = src.tagName.toUpperCase()) && ( terom@27: tag_name=='INPUT' || terom@27: tag_name=='SELECT' || terom@27: tag_name=='OPTION' || terom@27: tag_name=='BUTTON' || terom@27: tag_name=='TEXTAREA')) return; terom@27: terom@27: var pointer = [Event.pointerX(event), Event.pointerY(event)]; terom@27: var pos = Position.cumulativeOffset(this.element); terom@27: this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) }); terom@27: terom@27: Draggables.activate(this); terom@27: Event.stop(event); terom@27: } terom@27: }, terom@27: terom@27: startDrag: function(event) { terom@27: this.dragging = true; terom@27: if(!this.delta) terom@27: this.delta = this.currentDelta(); terom@27: terom@27: if(this.options.zindex) { terom@27: this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0); terom@27: this.element.style.zIndex = this.options.zindex; terom@27: } terom@27: terom@27: Draggables.notify('onStart', this, event); terom@27: }, terom@27: terom@27: updateDrag: function(event, pointer) { terom@27: if(!this.dragging) this.startDrag(event); terom@27: terom@27: Draggables.notify('onDrag', this, event); terom@27: terom@27: this.draw(pointer); terom@27: if(this.options.change) this.options.change(this); terom@27: terom@27: // fix AppleWebKit rendering terom@27: if(Prototype.Browser.WebKit) window.scrollBy(0,0); terom@27: terom@27: Event.stop(event); terom@27: }, terom@27: terom@27: finishDrag: function(event, success) { terom@27: this.dragging = false; terom@27: terom@27: Draggables.notify('onEnd', this, event); terom@27: terom@27: var d = this.currentDelta(); terom@28: this.delta = d; terom@27: terom@27: if(this.options.zindex) terom@27: this.element.style.zIndex = this.originalZ; terom@27: terom@27: Draggables.deactivate(this); terom@27: }, terom@27: terom@27: keyPress: function(event) { terom@27: if(event.keyCode!=Event.KEY_ESC) return; terom@27: this.finishDrag(event, false); terom@27: Event.stop(event); terom@27: }, terom@27: terom@27: endDrag: function(event) { terom@27: if(!this.dragging) return; terom@27: this.finishDrag(event, true); terom@27: Event.stop(event); terom@27: }, terom@27: terom@27: draw: function(point) { terom@27: var pos = Position.cumulativeOffset(this.element); terom@27: terom@27: var d = this.currentDelta(); terom@27: pos[0] -= d[0]; pos[1] -= d[1]; terom@27: terom@27: var p = [0,1].map(function(i){ terom@27: return (point[i]-pos[i]-this.offset[i]) terom@27: }.bind(this)); terom@27: terom@27: var style = this.element.style; terom@27: if((!this.options.constraint) || (this.options.constraint=='horizontal')) terom@27: style.left = p[0] + "px"; terom@27: if((!this.options.constraint) || (this.options.constraint=='vertical')) terom@27: style.top = p[1] + "px"; terom@27: terom@27: if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering terom@27: }, terom@28: terom@27: }); terom@27: terom@27: Draggable._dragging = { }; terom@27: