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