draggable = {

  dragObj:       null,
  cursorStartX:  0,
  cursorStartY:  0,
  elementStartX: 0,
  elementStartY: 0,
  dragGofn:      null,
  dragStopfn:    null,

  startDrag: function(event) {
    this.dragObj = Event.element(event);
    // if the target of the event is not a "draggable" element, then search
    // through it's parents for an element that is draggable.
    // if we can't find a draggable element before reaching the root document
    // element, then bail out
    while (!Element.hasClassName(this.dragObj, "draggable")) {
         this.dragObj = $(this.dragObj.parentNode);
    }
    this.cursorStartX = Event.pointerX(event);
    this.cursorStartY = Event.pointerY(event);
    this.elementStartX = parseInt(this.dragObj.style.left, 10);
    this.elementStartY = parseInt(this.dragObj.style.top, 10);
    Event.observe(this.dragObj, 'mousemove', draggable.dragGofn);
    Event.observe(this.dragObj, 'mouseup', draggable.dragStopfn);
  },

  dragGo: function(event) {
    var x, y;
    x = Event.pointerX(event);
    y = Event.pointerY(event);

    // move the target object
    this.dragObj.style.left = (x - this.cursorStartX + this.elementStartX) + "px";
    this.dragObj.style.top = (y - this.cursorStartY + this.elementStartY) + "px";

    Event.stop(event);
  },

  dragStop: function(event) {
    // Stop capturing mousemove and mouseup events.
    Event.stopObserving(this.dragObj, 'mousemove', draggable.dragGofn);
    Event.stopObserving(this.dragObj, 'mouseup', draggable.dragStopfn);
    this.dragObj = null;

    Event.stop(event);
  },

  registerEvents: function() {
    this.dragGofn = this.dragGo.bindAsEventListener();
    this.dragStopfn = this.dragStop.bindAsEventListener();

    $$(".draggable").each(function(element) {
        Event.observe(element, 'mousedown', draggable.startDrag.bindAsEventListener());
    });
  }

}
