Ok, here's the best working version I can come up with.  There's still a
little bit of choppiness, especially in Opera and Safari.  Mozilla is
pretty smooth, at least on my computer.  Someone who knows the draggable
code might know better how to smooth out the jerkiness; I dunno.  It
would be awesome if Thomas could include this in the scriptaculous
library, but I imagine he won't want to add something tested so little
just before a major release.  I was able to get this working on IE 5.5 &
6.0, Firefox 1.0.7, Safari 1.3, and Opera 8.5.  Scrolling up and left is
jerkier than down and right on all of them, and sometimes it renders the
dragging element in the middle of the page instead of where the cursor
is (it flickers back and forth).  Not sure how to correct that.  So,
here's the code, hopefully someone a little more intimately familiar
with scriptaculous can work out the kinks and get it included.

Thanks,
Greg

Object.extend(Draggable.prototype, {
  oldDraw: Draggable.prototype.draw,
  draw: function(event) {
    this.oldDraw(event);
    this.scrollIntoView();
  },
  scrollIntoView: function() {
    // set up to do 4px jumps every 100ms - might need adjusting
    this.scrollBy       = 4;
    this.scrollTimeout  = 100;

    var offsets = Position.cumulativeOffset(this.element);
    var x = offsets[0];
    var y = offsets[1];
    var scrollX = 0;
    var scrollY = 0;
    if (x < document.body.scrollLeft + this.scrollBy || y <
document.body.scrollTop + this.scrollBy) {
      if (x < document.body.scrollLeft + this.scrollBy && x >
(this.scrollBy - 1)) {
        scrollX = -this.scrollBy;
      }
      if (y < document.body.scrollTop  + this.scrollBy && y >
(this.scrollBy - 1)) {
        scrollY = -this.scrollBy;
      }
    }
    else {
      var elDimensions  = Element.getDimensions(this.element);
      if (! (this.winDimensions && this.maxDimensions)) {
        Event.observe(window, 'resize', function () { this.winDimensions
= null; this.maxDimensions = null; }.bindAsEventListener(this));
        this.winDimensions = Element.getDimensions(document.body);
        // to prevent Mozilla from extending the scrollbars indefinitely
        this.maxDimensions = (window.scrollMaxX != null &&
window.scrollMaxY != null)
          ? { 
              width:  this.winDimensions.width  + window.scrollMaxX,
              height: this.winDimensions.height + window.scrollMaxY
          }
          : { width: 1000000, height: 1000000 };
      }
     
      if ( x + elDimensions.width  > document.body.scrollLeft +
this.winDimensions.width - this.scrollBy
        && x + elDimensions.width + this.scrollBy <=
this.maxDimensions.width) {
        scrollX = this.scrollBy;
      }
      if ( y + elDimensions.height > document.body.scrollTop +
this.winDimensions.height - this.scrollBy
        && y + elDimensions.height + this.scrollBy <=
this.maxDimensions.height) {
        scrollY = this.scrollBy;
      }
    }
    if (scrollX != 0 || scrollY != 0) {
      var oldScroll = [document.body.scrollLeft,
document.body.scrollTop];
      window.scrollTo(document.body.scrollLeft + scrollX,
document.body.scrollTop + scrollY);
      // if scrolling had no effect, then we're at the edge (fix for
Opera)
      if (scrollX != 0 && document.body.scrollLeft == oldScroll[0] &&
this.maxDimensions.width == 1000000) {
        this.maxDimensions.width = document.body.scrollLeft +
this.winDimensions.width;
      }
      else if (scrollX != 0) {
        var currX = parseInt(this.element.style.left.replace(/px/,''));
        this.element.style.left = (currX + scrollX > 0)
          ? (currX + scrollX) + 'px' : '0px';
      }
      if (scrollY != 0 && document.body.scrollTop == oldScroll[1] &&
this.maxDimensions.height == 1000000) {
        this.maxDimensions.height = document.body.scrollTop +
this.winDimensions.height;
      }
      else if (scrollY != 0) {
        var currY = parseInt(this.element.style.top.replace(/px/,''));
        this.element.style.top  = (currY + scrollY > 0)
          ? (currY + scrollY) + 'px' : '0px';
      }
      this.movedSinceScrolled = false;
    }

    // if we still have an active drag but the mouse hasn't moved since
we started
    // scrolling, keep scrolling until they move it again
    if (this.active && ! this.movedSinceScrolled) {
      setTimeout(this.scrollIntoView.bind(this), this.scrollTimeout);
    }
  },
  oldUpdate: Draggable.prototype.update,
  update: function(event) {
    if (this.active) {
      this.movedSinceScrolled = true;
    }
    this.oldUpdate(event);
  }
});
_______________________________________________
Rails-spinoffs mailing list
[email protected]
http://lists.rubyonrails.org/mailman/listinfo/rails-spinoffs

Reply via email to