My Secret Life as a Spaghetti Coder
home | about | contact | privacy statement
I was having trouble with dragging and dropping elements using Scriptaculous's dragdrop.js. Apparently, I'm not the only one. The problem was:
I have a div with overflow = auto, so when there is more content than the size of the div, scrollbars appear. My draggables and droppables are all elements inside of that div. Everything works fine when the scrollbar is scrolled all the way to the top, but when you scroll it down any amount, the draggables fail.
There are plenty of potential solutions out there, but none of them worked for me. I would get the scrolling working, and then the draggable would move away from the cursor. I'd get it in sync with the mouse cursor and the scrolling would get crazy again. I'd fix that and then no matter where I dropped it, if the div had been scrolled, dropping would fail.

Here's how I fixed the problem:
  1. In the Draggable#updateDrag function (~ line 356), on the first line, I changed the value of the pointer argument to take into account how much the container had scrolled:

    pointer = new Array(pointer[0] + this.options.scroll.scrollLeft, pointer[1] + this.options.scroll.scrollTop);

    At least one of the solutions I recall seeing mentioned this.

  2. In the same function, I changed the first two elements in the p array before the last two elements get pushed onto it:

    p = new Array(p[0] + this.options.scroll.scrollLeft, p[1] + this.options.scroll.scrollTop);

    This also just takes into account how far the container has been scrolled.

  3. To ensure my droppables were able to receive the draggables given the adjusted coordinates, we need to adjust the scroll position just as we did above. First, I adjusted the code in my webpage that produces the droppables and added a scroll parameter that should be the name of the element that scrolls (the same parameter the draggable accepts):

    Droppables.add('slot_1_7_2', { scroll: 'weeklycalendar' });

    Since Droppable elements don't generally take a scroll option, we'll need to modify that code in Scriptaculous's dragdrop.js file as well. In the Droppable#fire function (~ line 109) add the folling lines under Position.prepare();:

    var point = [Event.pointerX(event), Event.pointerY(event)];
    if(this.last_active.scroll){
      point[0] += $(this.last_active.scroll).scrollLeft;
      point[1] += $(this.last_active.scroll).scrollTop;
    }

    Finally, just underneath that where it calls this.isAffected, change the first parameter from [Event.pointerX(event), Event.pointerY(event)] to use the variable we created above, pointer.
That should be it. If you've tried the above and still get problems, feel free to leave a comment below, or contact me and I'll do my best to help out.

I haven't submitted a patch because I didn't check to see that this was a general solution. It seems like it should be, but without testing it outside my intended usage, I don't think it'd be accepted anyway. Quite frankly, I'm not thrilled about adding a new option to droppables, but it seemed like the simplest route to fix my problem at the time.

Yes, I tried setting includeScrollOffsets to true and using Position#withinIncludingScrolloffsets in Prototype, and that failed for me too.

Hey! Why don't you make your life easier and subscribe to the full post or short blurb RSS feed? I'm so confident you'll love my smelly pasta plate wisdom that I'm offering a no-strings-attached, lifetime money back guarantee!


Comments
Leave a comment

Hi Sam...Could you post the code modified?? Because I got an error and maybe I'm doing something wrong.

Thanks

Posted by Jorge Alvarez on Apr 08, 2010 at 01:38 PM UTC - 6 hrs

Yes, I'll post it when I've got it handy - give me until tomorrow for that.

Posted by Sammy Larbi on Apr 08, 2010 at 02:32 PM UTC - 6 hrs

ok... no problem!! Thanks!

Posted by Jorge Alvarez on Apr 08, 2010 at 02:36 PM UTC - 6 hrs

Jorge,

The modified dragdrop.js file is here: http://www.codeodor.com/code/dragdrop.js

Posted by Sammy Larbi on Apr 09, 2010 at 04:58 PM UTC - 6 hrs

Let me know how it goes!

Posted by Sammy Larbi on Apr 09, 2010 at 05:02 PM UTC - 6 hrs

Hi Sammy thanks for this post, much appreciated! Unfortunately your solution doesn't quite work for me - after adding your lines the draggable is offset right away by the amount that I'm scrolled down in the container when I start dragging (seems logical as you're changing the value of the pointer param by the scrolling offset).

I even tried it with the dragdrop.js you posted on http://www.codeodor.com/code/dragdrop.js (adding the new Droppable param in my code of course). Any ideas? I can provide a short screencast with the problem if it helps.

Posted by Michael on Apr 23, 2010 at 05:02 AM UTC - 6 hrs

Actually think I just fixed the problem using Daniele's solution from https://prototype.lighthouseapp.com/projects/8887/... (well, most of it, anyway)

Thanks!

Posted by Michael on Apr 23, 2010 at 06:14 AM UTC - 6 hrs

Michael, thanks for sharing what ended up helping. Now that I see that code, I remember looking at isAffected and having a failure dropping, so I'll need to look back and make sure I uploaded the right code, or try to remember if something else ended up fixing it.

Thanks again!

Posted by Sammy Larbi on Apr 23, 2010 at 06:43 AM UTC - 6 hrs

Hi,

Here is what I wrote to have it running under IE 8.0.6 & Firefox 3.6.3:

Make draggable the elements (with border) in the "width:100px;scrollable:auto" container:
function makeDraggable(container,tag) {

if(!container || !tag) { return false; }
$(container).select(tag).each( function(o) {
new Draggable(o,{
starteffect: function(e){makeDragVisible(container,e);},
endeffect: function(e){e.setStyle({'position':'','width':'','cursor':''});},
zindex: 1000
// , revert: ... // the other options
});
});

}

function makeDragVisible(container,element) {

if(!container || !element) { return false; }
var i=$(container).getStyle('width');
i=i.replace('px','');
i=Math.round(i-20)+'px';
element.setStyle({'width':i,'z-index':1000,'position':'absolute','cursor':'move'});
//
$(container).setStyle({});

}

Important notes: (1) the z-index is repeated (2) notice the container loss of style at the end of 'starteffect'. Cursor and width are simply there to keep the drag user friendly.

I hope it helps.

Yours,
Nicolas

Posted by Nicolas on Jun 18, 2010 at 02:12 AM UTC - 6 hrs

Thanks for sharing your work, Nicolas!

Posted by Sammy Larbi on Jun 18, 2010 at 08:26 AM UTC - 6 hrs

After the line:
var pos = Position.cumulativeOffset(this.element);
in initDrag, I've added the following two lines:

pointer[0] += this.options.scroll.scrollLeft;
pointer[1] += this.options.scroll.scrollTop;

This helps the ghostly drag'n'drop box to be displayed in the right place.

Posted by Tristan Rowley on Jul 15, 2010 at 06:06 AM UTC - 6 hrs

@Tristan: Thanks for contributing to helping anyone else who comes across this.

Posted by Sammy Larbi on Jul 15, 2010 at 07:45 AM UTC - 6 hrs

Hope you are still using this little widget! I have been using this plugin and it has been working well , until I upgraded to ff 9. now it completely does not respond to dragging.. when I attempt to drag , it just ends up selecting the raw text on the page (basically zero response). have you encountered these issues with ff 9?

Posted by Bavyaa on Jan 31, 2012 at 01:25 PM UTC - 6 hrs

Bavyaa,

I'm sorry to say I'm no longer using it. The project I was using it on ended up changing quite a bit, so that functionality was no longer needed. (Also, it moved on to jQuery instead of prototype + scriptaculous).

Sorry I couldn't be of any more help.

Do you have firebug installed? Does it give any indication of error for your problem? That would be my first step in trying to figure it out.

Posted by Sammy Larbi on Jan 31, 2012 at 01:53 PM UTC - 6 hrs

Hi Sammy

Thanks for the quick response. I do have firebug and I see no errors. The js file is pretty huge and am finding it hard to debug it (its like a shot in the dark!)

Posted by bavyaa on Jan 31, 2012 at 01:57 PM UTC - 6 hrs

I know it's a pain. Are you using the latest version of scriptaculous? If not, upgrading may help.

And outside that, I'd look for similar code inside the file and start putting breakpoints in those places with firebug, and examining the variables when it gets there to see if you can figure it out.

Good luck!

Posted by Sammy Larbi on Jan 31, 2012 at 04:35 PM UTC - 6 hrs

In prototype:

Position.includeScrollOffsets = true;

Including that line fixed everything for me.

Posted by Andrew on Feb 19, 2012 at 07:29 PM UTC - 6 hrs

Cool, thanks for the tip!

Posted by Sammy Larbi on Feb 20, 2012 at 06:50 AM UTC - 6 hrs

Leave a comment

Leave this field empty
Your Name
Email (not displayed, more info?)
Website

Comment:

Subcribe to this comment thread
Remember my details
Google
Web CodeOdor.com

Me
Picture of me

Topics
.NET (19)
AI/Machine Learning (14)
Answers To 100 Interview Questions (10)
Bioinformatics (2)
Business (1)
C and Cplusplus (6)
cfrails (22)
ColdFusion (78)
Customer Relations (15)
Databases (3)
DRY (18)
DSLs (11)
Future Tech (5)
Games (5)
Groovy/Grails (8)
Hardware (1)
IDEs (9)
Java (38)
JavaScript (4)
Linux (2)
Lisp (1)
Mac OS (4)
Management (15)
MediaServerX (1)
Miscellany (76)
OOAD (37)
Productivity (11)
Programming (168)
Programming Quotables (9)
Rails (31)
Ruby (67)
Save Your Job (58)
scriptaGulous (4)
Software Development Process (23)
TDD (41)
TDDing xorblog (6)
Tools (5)
Web Development (8)
Windows (1)
With (1)
YAGNI (10)

Resources
Agile Manifesto & Principles
Principles Of OOD
ColdFusion
CFUnit
Ruby
Ruby on Rails
JUnit



RSS 2.0: Full Post | Short Blurb
Subscribe by email:

Delivered by FeedBurner