Opened 7 years ago

Closed 7 years ago

Last modified 5 years ago

#16090 closed defect (fixed)

dojo/touch: on iOS6, the "touches" property is missing on the synthetic touch.move event

Reported by: Adrian Vasiliu Owned by: bill
Priority: high Milestone: 1.7.7
Component: Events Version: 1.8.0
Keywords: ios6 Cc:
Blocked By: Blocking:

Description

For "touchmove" native events, dojo/touch creates a synthetic touch.move event. Now, the trouble is that, in iOS6, this synthetic event does not have a "touches" property, while it does have it on iOS 4 and 5.

This is the cause of a regression on iOS6 that can be seen in demos/touch/demo.html: you can't rotate the pie chart using the two-finger rotate gesture (while it works fine on iOS 4.3.3, 5.0.1 and 5.1.1).

Reproduced on an iPhone 4S under iOS 6 (6.0), using any recent Dojo version (initial 1.8, 1.8-patch or trunk).

The attached test_bug-synthetic-event-ios6.html is a simple test case which demonstrates the difference of behavior on iOS6 vs. iOS4 or 5 while only relying on dojo/touch (no dependency on dojox/gesture, while demos/touch depends on both). How to reproduce:

  1. Run the test on iOS 4 or 5.
  2. Follow the indication written in the app itself (touch and move over the blue upper area, and check the log written in the white area).

=> You can see in the lower part of the window the log traces for three events: a touch.press, a touch.move, and a synthetic touch.move. For all of them, evt.touches is NOT undefined. So far so good.

  1. Run the same test on an iOS6 device.

=> evt.touches is now undefined for the synthetic touch.move (and only for this event).

Attachments (2)

test_bug-synthetic-event-ios6.html (2.8 KB) - added by Adrian Vasiliu 7 years ago.
Test case demonstrating the missing "touches" property on synthetic events on iOS6
fix_synthetic-event-ios6.patch (845 bytes) - added by Adrian Vasiliu 7 years ago.
Fix missing "touches" property of synthetic event on iOS6 - Adrian Vasiliu, IBM, CCLA

Download all attachments as: .zip

Change History (22)

comment:1 Changed 7 years ago by Adrian Vasiliu

Digging into it, it appears the bug is due to a change in the recently released iOS6/webkit. It goes this way:

dojo/touch creates the synthetic event by

lang.mixin({}, evt, { ... additional properties ...});

This is supposed to copy the properties of the native event into the synthetic event. Now, lang.mixin iterates over the "enumerable properties" of the source object (here, our native event) using a "for...in" loop. On iOS 6, just as on iOS 4 and 5, the native event does have a "touches" property (you can print its value or assign it to a var), but on iOS6 it appears Apple decided that "touches" becomes a non-enumerable property, which is not hit by for...in. The attached test case also tests whether "e.touches" is hit by the "for...in" loop. As you can see from the log trace in the test, it is not hit anymore on iOS6.

The attached fix_synthetic-event-ios6.patch is a simple fix proposal: dojo/touch forces the copy of the "touches" property. This is only necessary (so far) on iOS6, while being harmless on iOS 4 or 5.

Last edited 7 years ago by Adrian Vasiliu (previous) (diff)

Changed 7 years ago by Adrian Vasiliu

Test case demonstrating the missing "touches" property on synthetic events on iOS6

Changed 7 years ago by Adrian Vasiliu

Fix missing "touches" property of synthetic event on iOS6 - Adrian Vasiliu, IBM, CCLA

comment:2 Changed 7 years ago by bill

Owner: changed from Kris Zyp to Adrian Vasiliu
Status: newpending

the "touches" property is missing on the synthetic touch.move event

I don't understand why you would expect the touch.move synthetic event to have a touches[] property. It certainly won't be there if the synthetic touch.move corresponds to a native mousemove event.

Not sure why demos/touch/demo.html needs this, perhaps it's a problem with the demo?

comment:3 Changed 7 years ago by Adrian Vasiliu

Status: pendingnew

Yes, it wasn't there if it corresponds to a native mousemove, and if we'd go with my suggested fix the "touches" property will be there but its value is undefined (as it can be tested with the attached test on a desktop browser). I thought it's overkill, but if you think it's worth adding code to make the addition of the "touches" property conditional, it can be done.

On the other side, the point that the suggested fix addresses is that "touches" should be there when it corresponds to a native touchmove event (not mousemove). On iOS 4 and 5 it used to be there, it's gone on iOS6, and we do have code which makes the assumption that the synthetic touch.move has the "touches" property just as the native touchmove. In my eyes, this assumption seems reasonable, do I miss something? For instance, in demos/touch/rotate.js the "touches" property is used for implementing the multi-touch rotation. This demo code gets the events from dojox/gesture/Base, which in turn relies on dojo/touch for the touch.move synthetic event.

comment:4 Changed 7 years ago by Eric Durocher

Keywords: ios6 added

comment:5 Changed 7 years ago by bill

Actually, I was suggesting to not change dojo/touch.js at all, instead fixing the problem upstream, for example by using touchOnly:true (the touchOnly flag defined in dojox/gesture/Base.js).

But that wouldn't work with dojox/gesture/tap.js, so I'm OK with your suggested change. Maybe adding evt.touches conditionally is better, in case someone has code like

if("touches" in evt and evt.touches.length == 2){ ...

I don't have a strong opinion though.

comment:6 Changed 7 years ago by bill

Milestone: tbd1.8.2
Owner: changed from Adrian Vasiliu to bill
Status: newassigned

I've been dealing with dojo/touch.js recently so I can check in this change. Marking for 1.8.2 since 1.8.1 is already in RC, although of course we should make all iOS6 fixes quickly.

comment:7 Changed 7 years ago by bill

In [29756]:

Make evt.touches available on iOS6 for touch.move synthetic event, refs #16090 !strict, fixing it on trunk. Thanks to Adrian for patch.

comment:8 Changed 7 years ago by cjolif

Priority: undecidedhigh

comment:9 Changed 7 years ago by Adrian Vasiliu

Thanks Bill. Just to answer your last points:

  • Well, changing the demo to use touchOnly:true smells to me more like a workaround than as a fix, because I'd think it's supposed to work also with touchOnly:false.
  • As far as I can see (and after testing on both desktop and mobile browsers), a code such as
    if("touches" in evt && evt.touches.length == 2){ ...
    

is as safe before as after this patch. On a desktop browser, the synthetic touch.move corresponds to a native touchmove, and in this case dojo/touch doesn't generate the touch.move using the code involved in the patch, so "touches" in evt is still false after the patch. The patch only impacts the case of touch.move corresponding to native touchmove, but in this case "touches" is anyway present/defined.

comment:10 Changed 7 years ago by bill

Milestone: 1.8.21.8.1

comment:11 Changed 7 years ago by bill

Resolution: fixed
Status: assignedclosed

In [29759]:

Make evt.touches available on iOS6 for touch.move synthetic event, fixes #16090 !strict on 1.8/ branch. Thanks to Adrian for patch.

comment:12 Changed 7 years ago by nickmaynard

Sorry to spoil the party here, but I just worked around this problem, with one change ... not only was event.touches missing, but also event.targetTouches and event.changedTouches.

Sadly I can't provide detailed debugging information down to the lack of a Mac (for now).

comment:13 Changed 7 years ago by Adrian Vasiliu

Indeed, "touches" might not be the only one impacted by the same change in iOS6. Now the question is whether we work on it in a hurry right now, or we leave it for after 1.8.1. Is it critical for you that the fix for these other properties is also included in 1.8.1? Since you mention a workaround, I guess it's not critical.

By the way, what is the impacted code that you refer to? (from a grep, it looks like dojox/analytics would be a place where these properties are used in conjunction with dojo/touch). And the workaround you refer to is touchOnly:true? or a different one?

comment:14 Changed 7 years ago by Adrian Vasiliu

Yes, the same holds for all other event properties: altKey, changedTouches, ctrlKey, metaKey, shiftKey, targetTouches, touches, type.

Being too late to deal with it for Dojo 1.8.1, I've filled a new ticket: #16108 where I've attached a patch proposal. To be safer and given the number of the involved properties, this time I've implemented the fix conditionally (no-op except on iOS6). Also attached to #16108 a test case extended to cover all the properties.

comment:15 Changed 7 years ago by Adrian Vasiliu

iOS 6.0.1 is now out, and at a quick testing it appears the fix on our side is still useful.

comment:16 Changed 7 years ago by Adrian Vasiliu

The same holds for Safari included in iOS 6.1 beta (tested using the simulator).

comment:17 Changed 7 years ago by bill

In [30073]:

Don't make copy of event object. It appears to be unnecessary, and it triggers an iOS6 bug with properties in the event object being marked as non-enumerable. Refs #16108, #16090 !strict.

comment:18 Changed 7 years ago by bill

In [30095]:

Don't make copy of event object. It appears to be unnecessary, and it triggers an iOS6 bug with properties in the event object being marked as non-enumerable. Fixes #16108, #16090 on 1.8/ branch !strict.

comment:19 Changed 6 years ago by bill

In [31091]:

Workaround iOS6 problem (again) causing touches[] etc. to not be in synthetic event. Also removing code mapping dojotouchmove.preventDefault() back to original touchmove event since it doesn't seem to be needed. Refs #16090 !strict.

comment:20 Changed 5 years ago by bill

Milestone: 1.8.11.7.7

Backported to 1.7 in e7403082d02faba2e47cb645d2532dd2920f60b8.

Note: See TracTickets for help on using tickets.