2015-04-04 09:53:59 -07:00
|
|
|
// Licensed to the Software Freedom Conservancy (SFC) under one
|
|
|
|
|
// or more contributor license agreements. See the NOTICE file
|
|
|
|
|
// distributed with this work for additional information
|
|
|
|
|
// regarding copyright ownership. The SFC licenses this file
|
|
|
|
|
// to you under the Apache License, Version 2.0 (the
|
|
|
|
|
// "License"); you may not use this file except in compliance
|
|
|
|
|
// with the License. You may obtain a copy of the License at
|
2014-11-12 19:33:37 +00:00
|
|
|
//
|
2015-04-04 09:53:59 -07:00
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
2014-11-12 19:33:37 +00:00
|
|
|
//
|
2015-04-04 09:53:59 -07:00
|
|
|
// Unless required by applicable law or agreed to in writing,
|
|
|
|
|
// software distributed under the License is distributed on an
|
|
|
|
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
|
|
|
// KIND, either express or implied. See the License for the
|
|
|
|
|
// specific language governing permissions and limitations
|
|
|
|
|
// under the License.
|
2011-09-08 14:00:21 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @fileoverview The file contains an abstraction of a touch screen
|
|
|
|
|
* for simulating atomic touchscreen actions.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
goog.provide('bot.Touchscreen');
|
|
|
|
|
|
|
|
|
|
goog.require('bot');
|
2011-12-06 11:44:44 +00:00
|
|
|
goog.require('bot.Device');
|
|
|
|
|
goog.require('bot.Error');
|
|
|
|
|
goog.require('bot.ErrorCode');
|
2013-06-15 16:19:51 -07:00
|
|
|
goog.require('bot.dom');
|
2025-12-20 14:10:39 +00:00
|
|
|
goog.require('bot.events');
|
|
|
|
|
goog.require('bot.userAgent');
|
2015-06-18 18:58:06 -07:00
|
|
|
goog.require('goog.dom.TagName');
|
2011-09-08 14:00:21 +00:00
|
|
|
goog.require('goog.math.Coordinate');
|
2015-06-18 18:58:06 -07:00
|
|
|
goog.require('goog.userAgent.product');
|
2025-12-20 14:10:39 +00:00
|
|
|
goog.require('goog.utils');
|
2011-09-08 14:00:21 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* A TouchScreen that provides atomic touch actions. The metaphor
|
|
|
|
|
* for this abstraction is a finger moving above the touchscreen that
|
|
|
|
|
* can press and then release the touchscreen when specified.
|
|
|
|
|
*
|
|
|
|
|
* The touchscreen supports three actions: press, release, and move.
|
|
|
|
|
*
|
|
|
|
|
* @constructor
|
2011-12-06 11:44:44 +00:00
|
|
|
* @extends {bot.Device}
|
2011-09-08 14:00:21 +00:00
|
|
|
*/
|
2020-11-27 15:46:30 +00:00
|
|
|
bot.Touchscreen = function () {
|
2025-12-20 14:10:39 +00:00
|
|
|
bot.Device.call(this);
|
2011-12-06 11:44:44 +00:00
|
|
|
|
2013-03-10 13:56:37 -07:00
|
|
|
/** @private {!goog.math.Coordinate} */
|
2011-12-06 11:44:44 +00:00
|
|
|
this.clientXY_ = new goog.math.Coordinate(0, 0);
|
|
|
|
|
|
2013-03-10 13:56:37 -07:00
|
|
|
/** @private {!goog.math.Coordinate} */
|
2011-12-06 11:44:44 +00:00
|
|
|
this.clientXY2_ = new goog.math.Coordinate(0, 0);
|
2011-09-08 14:00:21 +00:00
|
|
|
};
|
2025-12-20 14:10:39 +00:00
|
|
|
goog.utils.inherits(bot.Touchscreen, bot.Device);
|
2011-12-06 11:44:44 +00:00
|
|
|
|
|
|
|
|
|
2013-03-10 13:56:37 -07:00
|
|
|
/** @private {boolean} */
|
2015-06-18 18:58:06 -07:00
|
|
|
bot.Touchscreen.prototype.fireMouseEventsOnRelease_ = true;
|
2011-12-06 11:44:44 +00:00
|
|
|
|
|
|
|
|
|
2013-06-15 16:19:51 -07:00
|
|
|
/** @private {boolean} */
|
|
|
|
|
bot.Touchscreen.prototype.cancelled_ = false;
|
|
|
|
|
|
|
|
|
|
|
2013-03-10 13:56:37 -07:00
|
|
|
/** @private {number} */
|
2011-12-06 11:44:44 +00:00
|
|
|
bot.Touchscreen.prototype.touchIdentifier_ = 0;
|
|
|
|
|
|
|
|
|
|
|
2013-03-10 13:56:37 -07:00
|
|
|
/** @private {number} */
|
2011-12-06 11:44:44 +00:00
|
|
|
bot.Touchscreen.prototype.touchIdentifier2_ = 0;
|
|
|
|
|
|
|
|
|
|
|
2013-03-10 13:56:37 -07:00
|
|
|
/** @private {number} */
|
2013-06-15 16:19:51 -07:00
|
|
|
bot.Touchscreen.prototype.touchCounter_ = 2;
|
2011-09-08 14:00:21 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Press the touch screen. Pressing before moving results in an exception.
|
2011-12-06 11:44:44 +00:00
|
|
|
* Pressing while already pressed also results in an exception.
|
|
|
|
|
*
|
|
|
|
|
* @param {boolean=} opt_press2 Whether or not press the second finger during
|
|
|
|
|
* the press. If not defined or false, only the primary finger will be
|
|
|
|
|
* pressed.
|
2011-09-08 14:00:21 +00:00
|
|
|
*/
|
2020-11-27 15:46:30 +00:00
|
|
|
bot.Touchscreen.prototype.press = function (opt_press2) {
|
2012-02-19 20:32:56 +00:00
|
|
|
if (this.isPressed()) {
|
2011-12-06 11:44:44 +00:00
|
|
|
throw new bot.Error(bot.ErrorCode.UNKNOWN_ERROR,
|
2020-11-27 15:46:30 +00:00
|
|
|
'Cannot press touchscreen when already pressed.');
|
2011-12-06 11:44:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.touchIdentifier_ = this.touchCounter_++;
|
|
|
|
|
if (opt_press2) {
|
|
|
|
|
this.touchIdentifier2_ = this.touchCounter_++;
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-08 16:22:32 +00:00
|
|
|
if (bot.userAgent.IE_DOC_10) {
|
2015-06-18 18:58:06 -07:00
|
|
|
this.fireMouseEventsOnRelease_ = true;
|
2012-11-08 16:22:32 +00:00
|
|
|
this.firePointerEvents_(bot.Touchscreen.fireSinglePressPointer_);
|
|
|
|
|
} else {
|
2015-06-18 18:58:06 -07:00
|
|
|
this.fireMouseEventsOnRelease_ = this.fireTouchEvent_(
|
2020-11-27 15:46:30 +00:00
|
|
|
bot.events.EventType.TOUCHSTART);
|
2012-11-08 16:22:32 +00:00
|
|
|
}
|
2011-09-08 14:00:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Releases an element on a touchscreen. Releasing an element that is not
|
|
|
|
|
* pressed results in an exception.
|
|
|
|
|
*/
|
2020-11-27 15:46:30 +00:00
|
|
|
bot.Touchscreen.prototype.release = function () {
|
2012-02-19 20:32:56 +00:00
|
|
|
if (!this.isPressed()) {
|
2011-12-06 11:44:44 +00:00
|
|
|
throw new bot.Error(bot.ErrorCode.UNKNOWN_ERROR,
|
2020-11-27 15:46:30 +00:00
|
|
|
'Cannot release touchscreen when not already pressed.');
|
2011-12-06 11:44:44 +00:00
|
|
|
}
|
|
|
|
|
|
2013-06-15 16:19:51 -07:00
|
|
|
if (!bot.userAgent.IE_DOC_10) {
|
2012-11-08 16:22:32 +00:00
|
|
|
this.fireTouchReleaseEvents_();
|
2013-06-15 16:19:51 -07:00
|
|
|
} else if (!this.cancelled_) {
|
|
|
|
|
this.firePointerEvents_(bot.Touchscreen.fireSingleReleasePointer_);
|
2011-12-06 11:44:44 +00:00
|
|
|
}
|
2013-06-15 16:19:51 -07:00
|
|
|
bot.Device.clearPointerMap();
|
2012-02-19 20:32:56 +00:00
|
|
|
this.touchIdentifier_ = 0;
|
|
|
|
|
this.touchIdentifier2_ = 0;
|
2013-06-15 16:19:51 -07:00
|
|
|
this.cancelled_ = false;
|
2011-09-08 14:00:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Moves finger along the touchscreen.
|
|
|
|
|
*
|
|
|
|
|
* @param {!Element} element Element that is being pressed.
|
|
|
|
|
* @param {!goog.math.Coordinate} coords Coordinates relative to
|
|
|
|
|
* currentElement.
|
2011-12-06 11:44:44 +00:00
|
|
|
* @param {goog.math.Coordinate=} opt_coords2 Coordinates relative to
|
|
|
|
|
* currentElement.
|
|
|
|
|
*/
|
2020-11-27 15:46:30 +00:00
|
|
|
bot.Touchscreen.prototype.move = function (element, coords, opt_coords2) {
|
2012-02-19 20:32:56 +00:00
|
|
|
// The target element for touch actions is the original element. Hence, the
|
|
|
|
|
// element is set only when the touchscreen is not currently being pressed.
|
2012-11-08 16:22:32 +00:00
|
|
|
// The exception is IE10 which fire events on the moved to element.
|
2013-06-15 16:19:51 -07:00
|
|
|
var originalElement = this.getElement();
|
2012-11-08 16:22:32 +00:00
|
|
|
if (!this.isPressed() || bot.userAgent.IE_DOC_10) {
|
2012-02-19 20:32:56 +00:00
|
|
|
this.setElement(element);
|
|
|
|
|
}
|
2011-12-06 11:44:44 +00:00
|
|
|
|
2013-06-15 16:19:51 -07:00
|
|
|
var rect = bot.dom.getClientRect(element);
|
|
|
|
|
this.clientXY_.x = coords.x + rect.left;
|
|
|
|
|
this.clientXY_.y = coords.y + rect.top;
|
2011-12-06 11:44:44 +00:00
|
|
|
|
2025-12-20 14:10:39 +00:00
|
|
|
if (opt_coords2 !== undefined) {
|
2013-06-15 16:19:51 -07:00
|
|
|
this.clientXY2_.x = opt_coords2.x + rect.left;
|
|
|
|
|
this.clientXY2_.y = opt_coords2.y + rect.top;
|
2011-12-06 11:44:44 +00:00
|
|
|
}
|
|
|
|
|
|
2012-02-19 20:32:56 +00:00
|
|
|
if (this.isPressed()) {
|
2013-06-15 16:19:51 -07:00
|
|
|
if (!bot.userAgent.IE_DOC_10) {
|
2015-06-18 18:58:06 -07:00
|
|
|
this.fireMouseEventsOnRelease_ = false;
|
2012-11-08 16:22:32 +00:00
|
|
|
this.fireTouchEvent_(bot.events.EventType.TOUCHMOVE);
|
2013-06-15 16:19:51 -07:00
|
|
|
} else if (!this.cancelled_) {
|
|
|
|
|
if (element != originalElement) {
|
2015-06-18 18:58:06 -07:00
|
|
|
this.fireMouseEventsOnRelease_ = false;
|
2013-06-15 16:19:51 -07:00
|
|
|
}
|
|
|
|
|
if (bot.Touchscreen.hasMsTouchActionsEnabled_(element)) {
|
|
|
|
|
this.firePointerEvents_(bot.Touchscreen.fireSingleMovePointer_);
|
|
|
|
|
} else {
|
|
|
|
|
this.fireMSPointerEvent(bot.events.EventType.MSPOINTEROUT, coords, -1,
|
2020-11-27 15:46:30 +00:00
|
|
|
this.touchIdentifier_, MSPointerEvent.MSPOINTER_TYPE_TOUCH, true);
|
2013-06-15 16:19:51 -07:00
|
|
|
this.fireMouseEvent(bot.events.EventType.MOUSEOUT, coords, 0);
|
|
|
|
|
this.fireMSPointerEvent(bot.events.EventType.MSPOINTERCANCEL, coords, 0,
|
2020-11-27 15:46:30 +00:00
|
|
|
this.touchIdentifier_, MSPointerEvent.MSPOINTER_TYPE_TOUCH, true);
|
2013-06-15 16:19:51 -07:00
|
|
|
this.cancelled_ = true;
|
|
|
|
|
bot.Device.clearPointerMap();
|
|
|
|
|
}
|
2012-11-08 16:22:32 +00:00
|
|
|
}
|
2011-12-06 11:44:44 +00:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns whether the touchscreen is currently pressed.
|
|
|
|
|
*
|
|
|
|
|
* @return {boolean} Whether the touchscreen is pressed.
|
|
|
|
|
*/
|
2020-11-27 15:46:30 +00:00
|
|
|
bot.Touchscreen.prototype.isPressed = function () {
|
2012-02-19 20:32:56 +00:00
|
|
|
return !!this.touchIdentifier_;
|
2011-12-06 11:44:44 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* A helper function to fire touch events.
|
|
|
|
|
*
|
2025-12-20 14:10:39 +00:00
|
|
|
* @param {!bot.events.EventFactory_} type Event type.
|
2015-06-18 18:58:06 -07:00
|
|
|
* @return {boolean} Whether the event fired successfully or was cancelled.
|
2011-12-06 11:44:44 +00:00
|
|
|
* @private
|
|
|
|
|
*/
|
2020-11-27 15:46:30 +00:00
|
|
|
bot.Touchscreen.prototype.fireTouchEvent_ = function (type) {
|
2012-02-19 20:32:56 +00:00
|
|
|
if (!this.isPressed()) {
|
2011-12-06 11:44:44 +00:00
|
|
|
throw new bot.Error(bot.ErrorCode.UNKNOWN_ERROR,
|
2020-11-27 15:46:30 +00:00
|
|
|
'Should never fire event when touchscreen is not pressed.');
|
2011-12-06 11:44:44 +00:00
|
|
|
}
|
2012-02-19 20:32:56 +00:00
|
|
|
var touchIdentifier2;
|
|
|
|
|
var coords2;
|
|
|
|
|
if (this.touchIdentifier2_) {
|
|
|
|
|
touchIdentifier2 = this.touchIdentifier2_;
|
|
|
|
|
coords2 = this.clientXY2_;
|
2011-12-06 11:44:44 +00:00
|
|
|
}
|
2015-06-18 18:58:06 -07:00
|
|
|
return this.fireTouchEvent(type, this.touchIdentifier_, this.clientXY_,
|
2020-11-27 15:46:30 +00:00
|
|
|
touchIdentifier2, coords2);
|
2012-11-08 16:22:32 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* A helper function to fire touch events that occur on a release.
|
|
|
|
|
*
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
2020-11-27 15:46:30 +00:00
|
|
|
bot.Touchscreen.prototype.fireTouchReleaseEvents_ = function () {
|
2015-06-18 18:58:06 -07:00
|
|
|
var touchendSuccess = this.fireTouchEvent_(bot.events.EventType.TOUCHEND);
|
|
|
|
|
|
|
|
|
|
// In general, TouchScreen.Release will fire the legacy mouse events:
|
|
|
|
|
// mousemove, mousedown, mouseup, and click after the touch events have been
|
|
|
|
|
// fired. The click button should be zero and only one mousemove should fire.
|
|
|
|
|
// Under the following cases, mouse events should not be fired:
|
|
|
|
|
// 1. Movement has occurred since press.
|
|
|
|
|
// 2. Any event handler for touchstart has called preventDefault().
|
|
|
|
|
// 3. Any event handler for touchend has called preventDefault(), and browser
|
|
|
|
|
// is Mobile Safari or Chrome.
|
|
|
|
|
var fireMouseEvents =
|
2020-11-27 15:46:30 +00:00
|
|
|
this.fireMouseEventsOnRelease_ &&
|
|
|
|
|
(touchendSuccess || !(bot.userAgent.IOS ||
|
|
|
|
|
goog.userAgent.product.CHROME));
|
2015-06-18 18:58:06 -07:00
|
|
|
|
|
|
|
|
if (fireMouseEvents) {
|
2012-11-08 16:22:32 +00:00
|
|
|
this.fireMouseEvent(bot.events.EventType.MOUSEMOVE, this.clientXY_, 0);
|
|
|
|
|
var performFocus = this.fireMouseEvent(bot.events.EventType.MOUSEDOWN,
|
2020-11-27 15:46:30 +00:00
|
|
|
this.clientXY_, 0);
|
2012-11-08 16:22:32 +00:00
|
|
|
// Element gets focus after the mousedown event only if the mousedown was
|
|
|
|
|
// not cancelled.
|
|
|
|
|
if (performFocus) {
|
|
|
|
|
this.focusOnElement();
|
|
|
|
|
}
|
2013-06-15 16:19:51 -07:00
|
|
|
this.maybeToggleOption();
|
2015-02-24 23:55:39 -08:00
|
|
|
|
|
|
|
|
// If a mouseup event is dispatched to an interactable event, and that
|
|
|
|
|
// mouseup would complete a click, then the click event must be dispatched
|
|
|
|
|
// even if the element becomes non-interactable after the mouseup.
|
|
|
|
|
var elementInteractableBeforeMouseup =
|
2020-11-27 15:46:30 +00:00
|
|
|
bot.dom.isInteractable(this.getElement());
|
2012-11-08 16:22:32 +00:00
|
|
|
this.fireMouseEvent(bot.events.EventType.MOUSEUP, this.clientXY_, 0);
|
|
|
|
|
|
|
|
|
|
// Special click logic to follow links and to perform form actions.
|
2013-10-09 12:50:50 -04:00
|
|
|
if (!(bot.userAgent.WINDOWS_PHONE &&
|
2020-11-27 15:46:30 +00:00
|
|
|
bot.dom.isElement(this.getElement(), goog.dom.TagName.OPTION))) {
|
|
|
|
|
this.clickElement(this.clientXY_,
|
2015-02-24 23:55:39 -08:00
|
|
|
/* button */ 0,
|
|
|
|
|
/* opt_force */ elementInteractableBeforeMouseup);
|
2013-10-09 12:50:50 -04:00
|
|
|
}
|
2012-11-08 16:22:32 +00:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* A helper function to fire a sequence of Pointer events.
|
2013-06-15 16:19:51 -07:00
|
|
|
* @param {function(!bot.Touchscreen, !Element, !goog.math.Coordinate, number,
|
|
|
|
|
* boolean)} fireSinglePointer A function that fires a set of events for one
|
|
|
|
|
* finger.
|
2012-11-08 16:22:32 +00:00
|
|
|
* @private
|
|
|
|
|
*/
|
2020-11-27 15:46:30 +00:00
|
|
|
bot.Touchscreen.prototype.firePointerEvents_ = function (fireSinglePointer) {
|
2013-06-15 16:19:51 -07:00
|
|
|
fireSinglePointer(this, this.getElement(), this.clientXY_,
|
2020-11-27 15:46:30 +00:00
|
|
|
this.touchIdentifier_, true);
|
2013-06-15 16:19:51 -07:00
|
|
|
if (this.touchIdentifier2_ &&
|
2020-11-27 15:46:30 +00:00
|
|
|
bot.Touchscreen.hasMsTouchActionsEnabled_(this.getElement())) {
|
2013-06-15 16:19:51 -07:00
|
|
|
fireSinglePointer(this, this.getElement(),
|
2020-11-27 15:46:30 +00:00
|
|
|
this.clientXY2_, this.touchIdentifier2_, false);
|
2012-11-08 16:22:32 +00:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* A helper function to fire Pointer events related to a press.
|
|
|
|
|
*
|
|
|
|
|
* @param {!bot.Touchscreen} ts A touchscreen object.
|
2013-06-15 16:19:51 -07:00
|
|
|
* @param {!Element} element Element that is being pressed.
|
2012-11-08 16:22:32 +00:00
|
|
|
* @param {!goog.math.Coordinate} coords Coordinates relative to
|
|
|
|
|
* currentElement.
|
|
|
|
|
* @param {number} id The touch identifier.
|
|
|
|
|
* @param {boolean} isPrimary Whether the pointer represents the primary point
|
|
|
|
|
* of contact.
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
2020-11-27 15:46:30 +00:00
|
|
|
bot.Touchscreen.fireSinglePressPointer_ = function (ts, element, coords, id,
|
|
|
|
|
isPrimary) {
|
2012-11-08 16:22:32 +00:00
|
|
|
// Fire a mousemove event.
|
|
|
|
|
ts.fireMouseEvent(bot.events.EventType.MOUSEMOVE, coords, 0);
|
|
|
|
|
|
|
|
|
|
// Fire a MSPointerOver and mouseover events.
|
|
|
|
|
ts.fireMSPointerEvent(bot.events.EventType.MSPOINTEROVER, coords, 0, id,
|
2020-11-27 15:46:30 +00:00
|
|
|
MSPointerEvent.MSPOINTER_TYPE_TOUCH, isPrimary);
|
2012-11-08 16:22:32 +00:00
|
|
|
ts.fireMouseEvent(bot.events.EventType.MOUSEOVER, coords, 0);
|
|
|
|
|
|
|
|
|
|
// Fire a MSPointerDown and mousedown events.
|
|
|
|
|
ts.fireMSPointerEvent(bot.events.EventType.MSPOINTERDOWN, coords, 0, id,
|
2020-11-27 15:46:30 +00:00
|
|
|
MSPointerEvent.MSPOINTER_TYPE_TOUCH, isPrimary);
|
2012-11-08 16:22:32 +00:00
|
|
|
|
|
|
|
|
// Element gets focus after the mousedown event.
|
|
|
|
|
if (ts.fireMouseEvent(bot.events.EventType.MOUSEDOWN, coords, 0)) {
|
2013-06-15 16:19:51 -07:00
|
|
|
// For selectable elements, IE 10 fires a MSGotPointerCapture event.
|
|
|
|
|
if (bot.dom.isSelectable(element)) {
|
|
|
|
|
ts.fireMSPointerEvent(bot.events.EventType.MSGOTPOINTERCAPTURE, coords, 0,
|
2020-11-27 15:46:30 +00:00
|
|
|
id, MSPointerEvent.MSPOINTER_TYPE_TOUCH, isPrimary);
|
2013-06-15 16:19:51 -07:00
|
|
|
}
|
2012-11-08 16:22:32 +00:00
|
|
|
ts.focusOnElement();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* A helper function to fire Pointer events related to a release.
|
|
|
|
|
*
|
|
|
|
|
* @param {!bot.Touchscreen} ts A touchscreen object.
|
2013-06-15 16:19:51 -07:00
|
|
|
* @param {!Element} element Element that is being released.
|
2012-11-08 16:22:32 +00:00
|
|
|
* @param {!goog.math.Coordinate} coords Coordinates relative to
|
|
|
|
|
* currentElement.
|
|
|
|
|
* @param {number} id The touch identifier.
|
|
|
|
|
* @param {boolean} isPrimary Whether the pointer represents the primary point
|
|
|
|
|
* of contact.
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
2020-11-27 15:46:30 +00:00
|
|
|
bot.Touchscreen.fireSingleReleasePointer_ = function (ts, element, coords, id,
|
|
|
|
|
isPrimary) {
|
2012-11-08 16:22:32 +00:00
|
|
|
// Fire a MSPointerUp and mouseup events.
|
|
|
|
|
ts.fireMSPointerEvent(bot.events.EventType.MSPOINTERUP, coords, 0, id,
|
2020-11-27 15:46:30 +00:00
|
|
|
MSPointerEvent.MSPOINTER_TYPE_TOUCH, isPrimary);
|
2015-02-24 23:55:39 -08:00
|
|
|
|
|
|
|
|
// If a mouseup event is dispatched to an interactable event, and that mouseup
|
|
|
|
|
// would complete a click, then the click event must be dispatched even if the
|
|
|
|
|
// element becomes non-interactable after the mouseup.
|
|
|
|
|
var elementInteractableBeforeMouseup =
|
2020-11-27 15:46:30 +00:00
|
|
|
bot.dom.isInteractable(ts.getElement());
|
2013-06-15 16:19:51 -07:00
|
|
|
ts.fireMouseEvent(bot.events.EventType.MOUSEUP, coords, 0, null, 0, false,
|
2020-11-27 15:46:30 +00:00
|
|
|
id);
|
2012-11-08 16:22:32 +00:00
|
|
|
|
|
|
|
|
// Fire a click.
|
2015-06-18 18:58:06 -07:00
|
|
|
if (ts.fireMouseEventsOnRelease_) {
|
2013-06-15 16:19:51 -07:00
|
|
|
ts.maybeToggleOption();
|
2013-10-09 12:50:50 -04:00
|
|
|
if (!(bot.userAgent.WINDOWS_PHONE &&
|
2020-11-27 15:46:30 +00:00
|
|
|
bot.dom.isElement(element, goog.dom.TagName.OPTION))) {
|
2015-02-24 23:55:39 -08:00
|
|
|
ts.clickElement(ts.clientXY_,
|
|
|
|
|
/* button */ 0,
|
|
|
|
|
/* opt_force */ elementInteractableBeforeMouseup,
|
2020-11-27 15:46:30 +00:00
|
|
|
id);
|
2013-10-09 12:50:50 -04:00
|
|
|
}
|
2013-06-15 16:19:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (bot.dom.isSelectable(element)) {
|
|
|
|
|
// For selectable elements, IE 10 fires a MSLostPointerCapture event.
|
|
|
|
|
ts.fireMSPointerEvent(bot.events.EventType.MSLOSTPOINTERCAPTURE,
|
2020-11-27 15:46:30 +00:00
|
|
|
new goog.math.Coordinate(0, 0), 0, id,
|
|
|
|
|
MSPointerEvent.MSPOINTER_TYPE_TOUCH, false);
|
2013-06-15 16:19:51 -07:00
|
|
|
}
|
2012-11-08 16:22:32 +00:00
|
|
|
|
|
|
|
|
// Fire a MSPointerOut and mouseout events.
|
|
|
|
|
ts.fireMSPointerEvent(bot.events.EventType.MSPOINTEROUT, coords, -1, id,
|
2020-11-27 15:46:30 +00:00
|
|
|
MSPointerEvent.MSPOINTER_TYPE_TOUCH, isPrimary);
|
2013-06-15 16:19:51 -07:00
|
|
|
ts.fireMouseEvent(bot.events.EventType.MOUSEOUT, coords, 0, null, 0, false,
|
2020-11-27 15:46:30 +00:00
|
|
|
id);
|
2012-11-08 16:22:32 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* A helper function to fire Pointer events related to a move.
|
|
|
|
|
*
|
|
|
|
|
* @param {!bot.Touchscreen} ts A touchscreen object.
|
2013-06-15 16:19:51 -07:00
|
|
|
* @param {!Element} element Element that is being moved.
|
2012-11-08 16:22:32 +00:00
|
|
|
* @param {!goog.math.Coordinate} coords Coordinates relative to
|
|
|
|
|
* currentElement.
|
|
|
|
|
* @param {number} id The touch identifier.
|
|
|
|
|
* @param {boolean} isPrimary Whether the pointer represents the primary point
|
|
|
|
|
* of contact.
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
2020-11-27 15:46:30 +00:00
|
|
|
bot.Touchscreen.fireSingleMovePointer_ = function (ts, element, coords, id,
|
|
|
|
|
isPrimary) {
|
2012-11-08 16:22:32 +00:00
|
|
|
// Fire a MSPointerMove and mousemove events.
|
|
|
|
|
ts.fireMSPointerEvent(bot.events.EventType.MSPOINTERMOVE, coords, -1, id,
|
2020-11-27 15:46:30 +00:00
|
|
|
MSPointerEvent.MSPOINTER_TYPE_TOUCH, isPrimary);
|
2013-06-15 16:19:51 -07:00
|
|
|
ts.fireMouseEvent(bot.events.EventType.MOUSEMOVE, coords, 0, null, 0, false,
|
2020-11-27 15:46:30 +00:00
|
|
|
id);
|
2013-06-15 16:19:51 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* A function that determines whether an element can be manipulated by the user.
|
|
|
|
|
* The msTouchAction style is queried and an element can be manipulated if the
|
|
|
|
|
* style value is none. If an element cannot be manipulated, then move gestures
|
|
|
|
|
* will result in a cancellation and multi-touch events will be prevented. Tap
|
|
|
|
|
* gestures will still be allowed. If not on IE 10, the function returns true.
|
|
|
|
|
*
|
|
|
|
|
* @param {!Element} element The element being manipulated.
|
|
|
|
|
* @return {boolean} Whether the element can be manipulated.
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
2020-11-27 15:46:30 +00:00
|
|
|
bot.Touchscreen.hasMsTouchActionsEnabled_ = function (element) {
|
2013-06-15 16:19:51 -07:00
|
|
|
if (!bot.userAgent.IE_DOC_10) {
|
|
|
|
|
throw new Error('hasMsTouchActionsEnable should only be called from IE 10');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Although this particular element may have a style indicating that it cannot
|
|
|
|
|
// receive javascript events, its parent may indicate otherwise.
|
|
|
|
|
if (bot.dom.getEffectiveStyle(element, 'ms-touch-action') == 'none') {
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
var parent = bot.dom.getParentElement(element);
|
|
|
|
|
return !!parent && bot.Touchscreen.hasMsTouchActionsEnabled_(parent);
|
|
|
|
|
}
|
2011-09-08 14:00:21 +00:00
|
|
|
};
|