Skip to content

Commit 1fd03d5

Browse files
committed
Prevent mouse events from firing if touchstart or touchend was canceled.
On behalf of Google engineers
1 parent bdf4170 commit 1fd03d5

File tree

2 files changed

+73
-15
lines changed

2 files changed

+73
-15
lines changed

javascript/atoms/test/touchscreen_test.html

+45
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,51 @@
413413
assertThrows('Pressing when already pressed should throw an exception',
414414
goog.bind(touchscreen.press, touchscreen));
415415
}
416+
417+
function testPreventDefaultOnTouchstart() {
418+
if (!bot.events.SUPPORTS_TOUCH_EVENTS) {
419+
return;
420+
}
421+
goog.events.listen(target, goog.events.EventType.TOUCHSTART, function(e) {
422+
e.preventDefault();
423+
});
424+
touchscreen.move(target, new goog.math.Coordinate(0, 0));
425+
touchscreen.press();
426+
touchscreen.release();
427+
if (bot.userAgent.IE_DOC_10) {
428+
assertEvents(msPointerDownEvents(target),
429+
msPointerUpEventsWithClick(target));
430+
} else {
431+
assertEvents([goog.events.EventType.TOUCHSTART, target, 1,
432+
goog.events.EventType.TOUCHEND, target, 1]);
433+
}
434+
}
435+
436+
function testPreventDefaultOnTouchend() {
437+
if (!bot.events.SUPPORTS_TOUCH_EVENTS) {
438+
return;
439+
}
440+
goog.events.listen(target, goog.events.EventType.TOUCHEND, function(e) {
441+
e.preventDefault();
442+
});
443+
touchscreen.move(target, new goog.math.Coordinate(0, 0));
444+
touchscreen.press();
445+
touchscreen.release();
446+
if (bot.userAgent.IE_DOC_10) {
447+
assertEvents(msPointerDownEvents(target),
448+
msPointerUpEventsWithClick(target));
449+
} else {
450+
var events = [goog.events.EventType.TOUCHSTART, target, 1,
451+
goog.events.EventType.TOUCHEND, target, 1];
452+
if (!bot.userAgent.IOS && !goog.userAgent.product.CHROME) {
453+
events.push(goog.events.EventType.MOUSEMOVE, target,
454+
goog.events.EventType.MOUSEDOWN, target,
455+
goog.events.EventType.MOUSEUP, target,
456+
goog.events.EventType.CLICK, target);
457+
}
458+
assertEvents(events);
459+
}
460+
}
416461
</script>
417462
</head>
418463
<body>

javascript/atoms/touchscreen.js

+28-15
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ goog.require('bot.Error');
2828
goog.require('bot.ErrorCode');
2929
goog.require('bot.dom');
3030
goog.require('bot.events.EventType');
31+
goog.require('goog.dom.TagName');
3132
goog.require('goog.math.Coordinate');
33+
goog.require('goog.userAgent.product');
3234

3335

3436

@@ -55,7 +57,7 @@ goog.inherits(bot.Touchscreen, bot.Device);
5557

5658

5759
/** @private {boolean} */
58-
bot.Touchscreen.prototype.hasMovedAfterPress_ = false;
60+
bot.Touchscreen.prototype.fireMouseEventsOnRelease_ = true;
5961

6062

6163
/** @private {boolean} */
@@ -88,16 +90,17 @@ bot.Touchscreen.prototype.press = function(opt_press2) {
8890
'Cannot press touchscreen when already pressed.');
8991
}
9092

91-
this.hasMovedAfterPress_ = false;
9293
this.touchIdentifier_ = this.touchCounter_++;
9394
if (opt_press2) {
9495
this.touchIdentifier2_ = this.touchCounter_++;
9596
}
9697

9798
if (bot.userAgent.IE_DOC_10) {
99+
this.fireMouseEventsOnRelease_ = true;
98100
this.firePointerEvents_(bot.Touchscreen.fireSinglePressPointer_);
99101
} else {
100-
this.fireTouchEvent_(bot.events.EventType.TOUCHSTART);
102+
this.fireMouseEventsOnRelease_ = this.fireTouchEvent_(
103+
bot.events.EventType.TOUCHSTART);
101104
}
102105
};
103106

@@ -153,11 +156,11 @@ bot.Touchscreen.prototype.move = function(element, coords, opt_coords2) {
153156

154157
if (this.isPressed()) {
155158
if (!bot.userAgent.IE_DOC_10) {
156-
this.hasMovedAfterPress_ = true;
159+
this.fireMouseEventsOnRelease_ = false;
157160
this.fireTouchEvent_(bot.events.EventType.TOUCHMOVE);
158161
} else if (!this.cancelled_) {
159162
if (element != originalElement) {
160-
this.hasMovedAfterPress_ = true;
163+
this.fireMouseEventsOnRelease_ = false;
161164
}
162165
if (bot.Touchscreen.hasMsTouchActionsEnabled_(element)) {
163166
this.firePointerEvents_(bot.Touchscreen.fireSingleMovePointer_);
@@ -189,6 +192,7 @@ bot.Touchscreen.prototype.isPressed = function() {
189192
* A helper function to fire touch events.
190193
*
191194
* @param {bot.events.EventType} type Event type.
195+
* @return {boolean} Whether the event fired successfully or was cancelled.
192196
* @private
193197
*/
194198
bot.Touchscreen.prototype.fireTouchEvent_ = function(type) {
@@ -202,8 +206,8 @@ bot.Touchscreen.prototype.fireTouchEvent_ = function(type) {
202206
touchIdentifier2 = this.touchIdentifier2_;
203207
coords2 = this.clientXY2_;
204208
}
205-
this.fireTouchEvent(type, this.touchIdentifier_, this.clientXY_,
206-
touchIdentifier2, coords2);
209+
return this.fireTouchEvent(type, this.touchIdentifier_, this.clientXY_,
210+
touchIdentifier2, coords2);
207211
};
208212

209213

@@ -213,13 +217,22 @@ bot.Touchscreen.prototype.fireTouchEvent_ = function(type) {
213217
* @private
214218
*/
215219
bot.Touchscreen.prototype.fireTouchReleaseEvents_ = function() {
216-
this.fireTouchEvent_(bot.events.EventType.TOUCHEND);
217-
218-
// If no movement occurred since press, TouchScreen.Release will fire the
219-
// legacy mouse events: mousemove, mousedown, mouseup, and click
220-
// after the touch events have been fired. The click button should be zero
221-
// and only one mousemove should fire.
222-
if (!this.hasMovedAfterPress_) {
220+
var touchendSuccess = this.fireTouchEvent_(bot.events.EventType.TOUCHEND);
221+
222+
// In general, TouchScreen.Release will fire the legacy mouse events:
223+
// mousemove, mousedown, mouseup, and click after the touch events have been
224+
// fired. The click button should be zero and only one mousemove should fire.
225+
// Under the following cases, mouse events should not be fired:
226+
// 1. Movement has occurred since press.
227+
// 2. Any event handler for touchstart has called preventDefault().
228+
// 3. Any event handler for touchend has called preventDefault(), and browser
229+
// is Mobile Safari or Chrome.
230+
var fireMouseEvents =
231+
this.fireMouseEventsOnRelease_ &&
232+
(touchendSuccess || !(bot.userAgent.IOS ||
233+
goog.userAgent.product.CHROME));
234+
235+
if (fireMouseEvents) {
223236
this.fireMouseEvent(bot.events.EventType.MOUSEMOVE, this.clientXY_, 0);
224237
var performFocus = this.fireMouseEvent(bot.events.EventType.MOUSEDOWN,
225238
this.clientXY_, 0);
@@ -331,7 +344,7 @@ bot.Touchscreen.fireSingleReleasePointer_ = function(ts, element, coords, id,
331344
id);
332345

333346
// Fire a click.
334-
if (!ts.hasMovedAfterPress_) {
347+
if (ts.fireMouseEventsOnRelease_) {
335348
ts.maybeToggleOption();
336349
if (!(bot.userAgent.WINDOWS_PHONE &&
337350
bot.dom.isElement(element, goog.dom.TagName.OPTION))) {

0 commit comments

Comments
 (0)