CreateJS/EaselJS — pull request #255 by cubica (2013-02-01 10:56:23+00:00)
Title: Fixed bug with mouse and touch events in iOS's UIWebView

I've discovered this while testing a canvas webapp built with easeljs that was hosted inside a UIWebView in an iPad app.

# Bug effects

After a mouse event is generated, Stage's internal _primaryPointerId value remains -1 indefinitely. The side effects are that subsequent touch events do not update Stage's mouseX and mouseY properties anymore, and the internal _pointerData hash is not cleaned after a touchEnd event, so its size grows indefinitely.

# Bug cause

In the UIWebView environment, the "browser" generates TouchEvents whenever the user touches the canvas, but it also generates MouseEvents whenever the user touches other HTML elements such as divs, anchors etc, possibly managed by DOMElement instances. Both kinds of events are handled by easeljs (provided Touch is enabled). When a mouseDown events is processed, the Stage instance calls the internal function`_getPointerData(-1)`:
```javascript
p._getPointerData = function(id) {
var data = this._pointerData[id];
if (!data) {
data = this._pointerData[id] = {x:0,y:0};
// if it's the mouse (id == NaN) or the first new touch, then make it the primary pointer id:
if (this._primaryPointerID == null) { this._primaryPointerID = id; }
}
return data;
}
```
So this sets `_primaryPointerID` to -1.
When the subsequent mouseUp event is processed, the stage instance calls
```javascript
this._handlePointerUp(-1, e, false /* clear argument */);
```
At the end of `_handlePointerUp`, there's the following code:
```javascript
if (clear) {
if (id == this._primaryPointerID) { this._primaryPointerID = null; }
delete(this._pointerData[id]);
} else { o.event = o.target = null; }
```
So `_primaryPointerID` remains -1.
When touch events are processed, `_getPointerData` is called again, with the id of the touch pointer as an argument, but since the `_primaryPointerID` is not null, the touch pointer doesn't become the `_primaryPointerID`.
When touchEnd is processed, `stage._handlePointerUp(id, e, true)` is called, but since the `_primaryPointerID` is still -1, the pointer data in `_pointerData` are not removed so they stay there indefinitely.
Moreover, when mouseMove or touchMove events are processed, the following function is called:
```javascript
p._updatePointerPosition = function(id, pageX, pageY) {

...

if (id == this._primaryPointerID) {
this.mouseX = o.x;
this.mouseY = o.y;
this.mouseInBounds = o.inBounds;
}
}
```
So those properties are not updated during touchMove events too.
My fix just involves `_getPointerData`, where `_primaryPointerID` is updated when it's null (no ongoing mouse or touch event) OR -1 (a mouse event is ongoing).
However, this solution probably isn't optimal, as overlapping mouse and touch events could mess things up with `_primaryPointerID`.
Another fix could be to always set `_primaryPointerID` to null in `_handlePointerUp`, even if the clear argument is false.
Anyway, the best thing would be to separate mouse and touch pointer data management (i.e., only using `_primaryPointerID` for touch events).