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:
-
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.
-
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.
-
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!
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
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
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