Opened 9 years ago

Closed 9 years ago

Last modified 7 years ago

#5740 closed feature (duplicate)

Drop/release fails on mobile platforms

Reported by: woodpile Owned by:
Priority: major Milestone: 2.0.0
Component: ui.droppable Version: 1.8.2
Keywords: mobile touch jquery ui droppable Cc:
Blocked by: Blocking:

Description

Using mobile safari on iPod Touch and iPad, using a draggable/droppable or a sortable, dragging works fine, but dropping fails. It is left hovering over where the touch was released. Touching the screen again where you want it dropped causes the drop to complete, but that's not proper.

I made use of Ross Boucher's stuff (http://rossboucher.com/2008/08/19/iphone-touch-events-in-javascript/) with Scriptaculous and it works great. Using the same code with jQuery UI, not the same results. I'm primarily using Sortables, but also draggables/droppables. The point is that the browser is connecting to events fine, but jQuery UI is not responding to the right events.

This patch: http://dev.jqueryui.com/ticket/4143 is interesting, but incomplete as it only works for iPhones. Remove the iPhone parts and make it more generic for any mobile/touch platform and it becomes a starting point.

Attachments (1)

test.html (3.1 KB) - added by woodpile 9 years ago.
Test case.

Download all attachments as: .zip

Change History (10)

Changed 9 years ago by woodpile

Attachment: test.html added

Test case.

comment:1 Changed 9 years ago by woodpile

I added a test case. Run that on mobile safari on a touch device and behavior is replicated. Dragging works, dropping does not without release and additional touch. I can help with any testing needed.

comment:2 Changed 9 years ago by davep

The TouchList object is empty on touchend, I was able to fix the above issue by using the last TouchList object when e.touches[0] is undefined.

Adding something like this:

      if (first != undefined) {
      	lastTouch = first;
      } else {
      	first = lastTouch;
      }

Should fix the above issue, for now :)

comment:3 Changed 9 years ago by davep

a couple other things..

You can get away with e.preventDefault() only being on the touchmove event, i had to do this so some other links would remain clickable.

some css you can add for webkit:

* {
  -webkit-touch-callout: none; /* prevent callout to copy image, etc when tap to hold */
  -webkit-text-size-adjust: none; /* prevent webkit from resizing text to fit */
  -webkit-tap-highlight-color: rgba(0,0,0,0); /* make transparent link selection, adjust last value opacity 0 to 1.0 */
  -webkit-user-select: none; /* prevent copy paste, to allow, change 'none' to 'text' */
}

comment:4 in reply to:  2 Changed 9 years ago by woodpile

Replying to davep:

The TouchList object is empty on touchend, I was able to fix the above issue by using the last TouchList object when e.touches[0] is undefined.

Adding something like this:

      if (first != undefined) {
      	lastTouch = first;
      } else {
      	first = lastTouch;
      }

Should fix the above issue, for now :)

Where might I add that? I dl'd the full UI and cannot find any pertinent strings. I've no objection to maintaining a local copy briefly, but would much prefer to see this fixed in the real codebase and available on google cdn. Also, I have all that css in already for webkit/mobile safari. Any help appreciated. Thanks!

comment:5 Changed 9 years ago by davep

My slightly updated event handler

 var lastTouch;

 function handleTouchEvent(e) {
  
  var touches = e.changedTouches,
   first = e.touches[0],
   type = '';
  
  // e.touches[0] is empty on touchend, use the last TouchList object instead
  if (first != undefined) {
   lastTouch = first;
  } else {
   first = lastTouch;
  }
   
  switch (e.type) {
   case 'touchstart':  type='mousedown'; break;
   case 'touchmove':   type='mousemove'; e.preventDefault(); break;
   case 'touchend':    type='mouseup';   break;
   default: return;
  }

  //initMouseEvent(type, canBubble, cancelable, view, clickCount,
  //           screenX, screenY, clientX, clientY, ctrlKey,
  //           altKey, shiftKey, metaKey, button, relatedTarget);
  var se = document.createEvent('MouseEvent');
  se.initMouseEvent(type, true, true, window, 1,
           first.screenX, first.screenY,
           first.clientX, first.clientY,
           false, false, false, false,
           0/*left*/, null);
  first.target.dispatchEvent(se);
  
  return;
 }

Note that i only prevent default behavior on touchmove, which works better for my needs.

comment:6 in reply to:  5 Changed 9 years ago by woodpile

Replying to davep:

My slightly updated event handler

Note that i only prevent default behavior on touchmove, which works better for my needs.

Awesome! That did it for me. Thank you very much! I also backed off the preventDefault to just touchmove and it works fine. Thanks again!

comment:7 Changed 9 years ago by Scott González

Priority: blockermajor
Type: bugfeature

comment:8 Changed 9 years ago by Scott González

Resolution: duplicate
Status: newclosed

Duplicate of #4143.

comment:9 Changed 7 years ago by Scott González

Milestone: 1.next2.0.0
Note: See TracTickets for help on using tickets.