yui/yui3 — pull request #986 by tilomitra (2013-07-11 17:25:47+00:00)
Title: Add Dual Listener and e.preventDefault() support to event-tap

This pull request addresses a long-standing issue to make events work well on devices that support both, touch and mouse inputs (such as the Chromebook Pixel). I've added this functionality to `event-tap` and I'd like a code review of it. Provided that you guys think that I have approached this in the right manner, I can add this functionality to `event-gestures` as well.

## What's in this PR

Historically, `event-tap` has had some shortcomings:

1. If you subscribed to the `tap` event, you couldn't call `event.preventDefault()` within the callback.
2. `tap` didn't work on devices which support both touch and mouse inputs. This is because of a bug in `event-touch`.

Both of these issues have been resolved in this pull request.

## Solving the dual-listener bug

The part of this pull request that I would like the most feedback on is how I have handled the dual listener issue. This is how it works (Refer to the code [in this commit](https://github.com/tilomitra/yui3/commit/9cbc2f655e46c69aa9ed56506cc4225eaabca7b9))

1. By default, subscribing to a `tap` event adds a listener for `[mousedown touchstart]` if it notices that `win.ontouchstart` exists.
2. Inside the `mousedown touchstart` callback, it checks to see whether a `mouse*` event or a `touch*` event occured. If touch, it sets up more `touch*` subscriptions, else if mouse, it sets up `mouse*` subscriptions. This prevents the `tap` event from firing twice, in case a browser fires mouse events after touch events (as shown below):

```
touchstart
touchend
mousedown
mouseup (this won't fire an additional tap event)
click (this is captured by modifying the fire() method)
```

It'll probably make more sense to look at the code: https://github.com/tilomitra/yui3/commit/9cbc2f655e46c69aa9ed56506cc4225eaabca7b9

Looking forward to some feedback!

## Tested on

Tested on Android 4.0.x, iOS6, IE6,7,8,9,10, Latest FF, Safari, Chrome

Note: I simulated the dual listener functionality by turning on the touch events flag in Chrome. More information about debugging touch events in Chrome here: https://developers.google.com/events/io/sessions/361772634