Skip to content
This repository was archived by the owner on Aug 1, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 31 additions & 12 deletions closure/goog/events/browserevent.js
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,19 @@ goog.events.BrowserEvent.IEButtonMap = [
goog.events.BrowserEvent.prototype.init = function(e, opt_currentTarget) {
var type = this.type = e.type;

/** @type {Touch} */
var relevantTouch = null;
if (type == goog.events.EventType.TOUCHSTART ||
type == goog.events.EventType.TOUCHMOVE) {
relevantTouch = e.targetTouches[0];
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After more thinking, and looking at #337, I think it's a mistake to rely on targetTouches. With multiple touches on the touch surface targetTouches[0] is unlikely to be the "relevant touch". See my comments in #337 for more details, and see the targetTouches definition on mdn. So as done in #337 I'm tempted to rewrite this whole block as follows:

  /**
   * On touch devices use the first "changed touch" as the relevant touch.
   * @type {Touch}
   */
  var relevantTouch = e.changedTouches ? e.changedTouches[0] : null;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's a branch implementing this: https://github.com/elemoine/closure-library/tree/targettouches. @mtsgrd, I'd be curious to know if that makes a difference with iOS 8.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mtsgrd this example is based on my targettouches branch: http://erilem.net/ngeo/layerorder-touch/layerorder.html. Does it work for you in iOS 8?

} else if (type == goog.events.EventType.TOUCHEND ||
type == goog.events.EventType.TOUCHCANCEL) {
relevantTouch = e.changedTouches[0];
}

// TODO(nicksantos): Change this.target to type EventTarget.
this.target = /** @type {Node} */ (e.target) || e.srcElement;
this.target = goog.isNull(relevantTouch) ?
/** @type {Node} */ (e.target) || e.srcElement : relevantTouch.target;

// TODO(nicksantos): Change this.currentTarget to type EventTarget.
this.currentTarget = /** @type {Node} */ (opt_currentTarget);
Expand All @@ -250,17 +261,25 @@ goog.events.BrowserEvent.prototype.init = function(e, opt_currentTarget) {

this.relatedTarget = relatedTarget;

// Webkit emits a lame warning whenever layerX/layerY is accessed.
// http://code.google.com/p/chromium/issues/detail?id=101733
this.offsetX = (goog.userAgent.WEBKIT || e.offsetX !== undefined) ?
e.offsetX : e.layerX;
this.offsetY = (goog.userAgent.WEBKIT || e.offsetY !== undefined) ?
e.offsetY : e.layerY;

this.clientX = e.clientX !== undefined ? e.clientX : e.pageX;
this.clientY = e.clientY !== undefined ? e.clientY : e.pageY;
this.screenX = e.screenX || 0;
this.screenY = e.screenY || 0;
if (!goog.isNull(relevantTouch)) {
this.clientX = relevantTouch.clientX !== undefined ?
relevantTouch.clientX : relevantTouch.pageX;
this.clientY = relevantTouch.clientY !== undefined ?
relevantTouch.clientY : relevantTouch.pageY;
this.screenX = relevantTouch.screenX || 0;
this.screenY = relevantTouch.screenY || 0;
} else {
// Webkit emits a lame warning whenever layerX/layerY is accessed.
// http://code.google.com/p/chromium/issues/detail?id=101733
this.offsetX = (goog.userAgent.WEBKIT || e.offsetX !== undefined) ?
e.offsetX : e.layerX;
this.offsetY = (goog.userAgent.WEBKIT || e.offsetY !== undefined) ?
e.offsetY : e.layerY;
this.clientX = e.clientX !== undefined ? e.clientX : e.pageX;
this.clientY = e.clientY !== undefined ? e.clientY : e.pageY;
this.screenX = e.screenX || 0;
this.screenY = e.screenY || 0;
}

this.button = e.button;

Expand Down
81 changes: 68 additions & 13 deletions closure/goog/events/browserevent_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ goog.setTestOnly('goog.events.BrowserEventTest');

goog.require('goog.events.BrowserEvent');
goog.require('goog.events.BrowserFeature');
goog.require('goog.math.Coordinate');
goog.require('goog.testing.PropertyReplacer');
goog.require('goog.testing.jsunit');
goog.require('goog.userAgent');
Expand Down Expand Up @@ -68,19 +69,19 @@ function testDefaultPrevented() {
function testIsButtonIe() {
stubs.set(goog.events.BrowserFeature, 'HAS_W3C_BUTTON', false);
assertIsButton(
createBrowserEvent('mousedown', 1),
createMouseEvent('mousedown', 1),
Button.LEFT,
true);
assertIsButton(
createBrowserEvent('click', 0),
createMouseEvent('click', 0),
Button.LEFT,
true);
assertIsButton(
createBrowserEvent('mousedown', 2),
createMouseEvent('mousedown', 2),
Button.RIGHT,
false);
assertIsButton(
createBrowserEvent('mousedown', 4),
createMouseEvent('mousedown', 4),
Button.MIDDLE,
false);
}
Expand All @@ -90,27 +91,27 @@ function testIsButtonWebkitMac() {
stubs.set(goog.userAgent, 'WEBKIT', true);
stubs.set(goog.userAgent, 'MAC', true);
assertIsButton(
createBrowserEvent('mousedown', 0),
createMouseEvent('mousedown', 0),
Button.LEFT,
true);
assertIsButton(
createBrowserEvent('mousedown', 0, true),
createMouseEvent('mousedown', 0, true),
Button.LEFT,
false);
assertIsButton(
createBrowserEvent('mousedown', 2),
createMouseEvent('mousedown', 2),
Button.RIGHT,
false);
assertIsButton(
createBrowserEvent('mousedown', 2, true),
createMouseEvent('mousedown', 2, true),
Button.RIGHT,
false);
assertIsButton(
createBrowserEvent('mousedown', 1),
createMouseEvent('mousedown', 1),
Button.MIDDLE,
false);
assertIsButton(
createBrowserEvent('mousedown', 1, true),
createMouseEvent('mousedown', 1, true),
Button.MIDDLE,
false);
}
Expand All @@ -120,23 +121,77 @@ function testIsButtonGecko() {
stubs.set(goog.userAgent, 'GECKO', true);
stubs.set(goog.userAgent, 'MAC', true);
assertIsButton(
createBrowserEvent('mousedown', 0),
createMouseEvent('mousedown', 0),
Button.LEFT,
true);
assertIsButton(
createBrowserEvent('mousedown', 2, true),
createMouseEvent('mousedown', 2, true),
Button.RIGHT,
false);
}

function createBrowserEvent(type, button, opt_ctrlKey) {
function testTouchEventHandling() {
var clientCoords = new goog.math.Coordinate(5, 5);
var screenCoords = new goog.math.Coordinate(10, 10);
var target = document.body;
var touchStart = createTargetTouchEvent('touchstart', target, clientCoords,
screenCoords);
var touchMove = createTargetTouchEvent('touchmove', target, clientCoords,
screenCoords);
var touchEnd = createChangedTouchEvent('touchend', target, clientCoords,
screenCoords);
var touchCancel = createChangedTouchEvent('touchcancel', target,
clientCoords, screenCoords);

assertEquals(clientCoords.x, touchStart.clientX);
assertEquals(clientCoords.y, touchStart.clientY);
assertEquals(target, touchStart.target);

assertEquals(screenCoords.x, touchMove.screenX);
assertEquals(screenCoords.y, touchMove.screenY);

assertEquals(clientCoords.x, touchEnd.clientX);
assertEquals(clientCoords.y, touchEnd.clientY);

assertEquals(screenCoords.x, touchCancel.screenX);
assertEquals(screenCoords.y, touchCancel.screenY);
assertEquals(target, touchCancel.target);
}

function createMouseEvent(type, button, opt_ctrlKey) {
return new goog.events.BrowserEvent({
type: type,
button: button,
ctrlKey: !!opt_ctrlKey
});
}

function createTargetTouchEvent(type, target, clientCoords, screenCoords) {
return new goog.events.BrowserEvent({
type: type,
targetTouches: [{
target: target,
clientX: clientCoords.x,
clientY: clientCoords.y,
screenX: screenCoords.x,
screenY: screenCoords.y
}]
});
}

function createChangedTouchEvent(type, target, clientCoords, screenCoords) {
return new goog.events.BrowserEvent({
type: type,
changedTouches: [{
target: target,
clientX: clientCoords.x,
clientY: clientCoords.y,
screenX: screenCoords.x,
screenY: screenCoords.y
}]
});
}

function assertIsButton(event, button, isActionButton) {
for (var key in Button) {
assertEquals(
Expand Down
22 changes: 0 additions & 22 deletions closure/goog/fx/dragger.js
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,6 @@ goog.fx.Dragger.prototype.startDrag = function(e) {

if (this.enabled_ && !this.dragging_ &&
(!isMouseDown || e.isMouseActionButton())) {
this.maybeReinitTouchEvent_(e);
if (this.hysteresisDistanceSquared_ == 0) {
if (this.fireDragStart_(e)) {
this.dragging_ = true;
Expand Down Expand Up @@ -550,7 +549,6 @@ goog.fx.Dragger.prototype.endDrag = function(e, opt_dragCanceled) {
this.cleanUpAfterDragging_();

if (this.dragging_) {
this.maybeReinitTouchEvent_(e);
this.dragging_ = false;

var x = this.limitX(this.deltaX);
Expand All @@ -575,33 +573,13 @@ goog.fx.Dragger.prototype.endDragCancel = function(e) {
};


/**
* Re-initializes the event with the first target touch event or, in the case
* of a stop event, the last changed touch.
* @param {goog.events.BrowserEvent} e A TOUCH... event.
* @private
*/
goog.fx.Dragger.prototype.maybeReinitTouchEvent_ = function(e) {
var type = e.type;

if (type == goog.events.EventType.TOUCHSTART ||
type == goog.events.EventType.TOUCHMOVE) {
e.init(e.getBrowserEvent().targetTouches[0], e.currentTarget);
} else if (type == goog.events.EventType.TOUCHEND ||
type == goog.events.EventType.TOUCHCANCEL) {
e.init(e.getBrowserEvent().changedTouches[0], e.currentTarget);
}
};


/**
* Event handler that is used on mouse / touch move to update the drag
* @param {goog.events.BrowserEvent} e Event object.
* @private
*/
goog.fx.Dragger.prototype.handleMove_ = function(e) {
if (this.enabled_) {
this.maybeReinitTouchEvent_(e);
// dx in right-to-left cases is relative to the right.
var sign = this.useRightPositioningForRtl_ &&
this.isRightToLeft_() ? -1 : 1;
Expand Down