Prototype / scriptaculous iPad dragdrop hack

I was really pleased when I got an iPad from the states a few months back.

I was really miffed that my app using prototype / scriptaculous didn’t dragdrop out of the box.

I looked around to see if anyone else had fixed the lib, to no avail, so I finally spent some of my wee small hours time hacking the library to support this.

The subtle differences in the API:

  • its “touchstart”, “touchend”, “touchmove” not “mousedown”, “mouseup”, “mousemove”
  • To work out if touch is supported use (just found out this isn’t supported in android):
    var supports = ('createTouch' in document)
  • There is no concept of a current pointer when your finger isn’t on the screen, so when you drop, you have to use the previous pointer (luckily already tracked in the dragdrop lib)
  • There is an array of touches on the iPad (for different fingers etc), so event.pageX is event.touches[0].pageX

dragdrop.js and prototype.js files attached

prototype.js
dragdrop.js

The bits that don’t work yet: the drag seems to be greedy right now, so I can’t activate links in the draggable.  Need to look at the webkitdragdrop.js lib to see how they handled that.

Thanks Thomas Fuchs, for scriptaculous in the first place, and secondly for the iPad demo which i ripped to bits to work out how it was put together.

15 comments

  1. Thanks a lot, you saved my day! It would be really great if you somehow find the time to fix the links inside a draggable – then it would be perfect for my needs already.

    Two more bugs that I found: if you scroll down a page and then try to move an object there, the browser jumps back to the top of the page. Also, the attribute scroll: window isn’t working properly – if you move an object down the page nothing happens, if you move it to the the right edge the iPad somehow seems to interpret it as a pinch out gesture.

    Thanks again!

  2. Hey michael
    Thanks for that, and letting me know about the 2 defects. I’m going to have to fix both these for the project I’m working on, just not sure if it’ll be tomorrow or next week. I’ll post an update once it’s done though. I noticed in some other scripts they disable the default behaviour of the browser to make it feel more like a native app. That should do the trick to kill the zooming. Need to make a big div tag to give it a try.

    P.s. If your just looking for iPad / iphone only support, the lib at http://www.gotproject.com/blog/post2.html looks quite good

  3. P.p.s. I don’t actually know if it’s an issue with links or grabbing the click event btw (probably the latter). Just remembered that my buttons were onclick not href, so it might work just now…

  4. Hey Ben,
    Thanks for the link, I didn’t know such a library exists. Unfortunately the project I’m working on is intended to be accessed mostly by desktop computers, the iPad is going to be used for presentation purposes only.

    My draggables contain both, href- and onclick-links. Neither ones are working so far.
    However, I just remembered that I have had some problems with those links before. If a draggable was moved by clicking on a link it contained, first the draggable-action was executed and afterwards the browser followed the link. To avoid this behaviour, I added a transparent div which overlays the draggable as soon as the onStart-event is triggered. It may not be the most intelligent solution, but for me – not being that much of a JS-professional – it did the trick. ;)

    Maybe there’s another issue with the iPad’s handling of the onStart-event, causing it to display my invisible divs permanently, hence preventing the links from being clicked. I don’t have my device here with me right now so I can’t confirm my idea … I will try this tomorrow.

  5. Me again. Just tested the link-bug. The handling of the onStart-event is fine, my div has nothing to do with the links not working. This really seems to be a scriptaculous-issue.

  6. Thanks Michael,

    I’ll take a look at it then. I’ve a few ideas on where I could look – I use onclick events in my div tags, so think it may have something to do with that (which fires when the touch comes back up, as I understand)

  7. as far as href’s well, i’ll need to play around…

  8. Looks like I’ve found a suspect in the non-scrolling defect.

    if(Prototype.Browser.WebKit) window.scrollBy(0,0);

    is wangalanged into line 417 of dragdrop.js for some reason. I’m tempted to remove it, as I can’t get my drag and drop rendering in on my mac laptop’s safari anyway…

  9. I’ve also looked at how onclick is handled in another lib. It basically checks to see if the draggable element has moved, and if it hasn’t, it fires the function that has been passed in for onClick (which makes sense as an onClick is a down and up).
    So it actually doesn’t look for any elements contained in the main one, and doesn’t seem to fire any attributes declared on any draggable element.
    I might have to resort to making a smaller handler inside the element I want to drag and have my buttons out of the handler, which is probably what I should’ve done in the beginning…

  10. Seems I just found a workaround for the links (both href and onclick). My draggables contain some divs and uls which then contain my links. If I set the CSS of those parent elements to position: absolute and give them a high z-index, they still move as well when the draggable is moved – and the links are working!
    Maybe this will work for you too.

  11. Thanks Michael. I’ll have a go at doing that. It also might be worth doing that using Javascript in the lib so I don’t have to work around it every time I use the libs

    cheers

  12. Err, you better forget my workaround. I discovered it yesterday just before I packed up work, hence I was too lazy to really test it. It works as long as the links are not fully positioned above the draggable (which happened in my case due to the new position attribute), but as soon as you move them back to where they belong, they deny work again.

    Anyways, I already found a new workaround. ;)
    I took a look at the Firefox-bugfix in the initDrag function at about line 330 and added all the HTML elements that contain my links to the if-statement:

    tag_name==’A’ ||
    tag_name==’H2′ ||

    All my links work perfect now, only a few exceptions don’t react *every* time I press them. But since all those exceptions are quite tiny icons (13 x 13 pixels), I’m willing to believe this is only because of my fat fingers. ;)

    By using this workaround, you will however lose the functionality to move a draggable while touching / clicking on one of the links respectively any element you stated in the if-clause. I don’t know if that’s a problem for you, in my case I can live with that.

  13. Star hack. Took me 5 minutes to copy your 2 files and get my small drag and drop page working on both desktop and ipad!

    Have you talked to scriptaculous to get this included in the standard lib ?

    tx again!

  14. Hi Pierre,

    I haven’t considered that, as there is a small problem with links not reacting on my iPad. If you follow Michael’s hack, it only works sometimes. I’m going to get a chance to fix it properly sometime soon as I’m re-writing parts of my app that needs this. I’d then feel comfortable submitting a patch.

  15. Hi,

    Regarding the onclick event. My application seems to work fine after putting
    if (!Draggables.supportsTouch) {
    Event.stop(event);
    }
    instead of only Event.stop(event);
    in the initDrag method. It looks that the original Event.stop() is only there to prevent text to be selected while dragging. I’m not sure though!

    Cheers and thanks for your “hacks”

Leave a comment