Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: improve types in touch code #6099

Merged
merged 1 commit into from
Apr 21, 2022
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
6 changes: 4 additions & 2 deletions core/gesture.js
Original file line number Diff line number Diff line change
Expand Up @@ -519,10 +519,12 @@ class Gesture {
return;
}

// TODO(#6097): Make types accurate, possibly by refactoring touch handling.
const typelessEvent = /** @type {?} */ (e);
if ((e.type.toLowerCase() === 'touchstart' ||
e.type.toLowerCase() === 'pointerdown') &&
e.pointerType !== 'mouse') {
Touch.longStart(e, this);
typelessEvent.pointerType !== 'mouse') {
Touch.longStart(typelessEvent, this);
}

this.mouseDownXY_ = new Coordinate(e.clientX, e.clientY);
Expand Down
78 changes: 55 additions & 23 deletions core/touch.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,19 @@ const {Gesture} = goog.requireType('Blockly.Gesture');
const {globalThis} = goog.require('Blockly.utils.global');


/**
* A mock event, created from either a mouse or touch event,
* with no more than one entry in the changedTouches array.
* @typedef {{
* type: string,
* changedTouches: Array<Touch>,
* target: Element,
* stopPropagation: function():void,
* preventDefault: function():void
* }}
*/
let PseudoEvent; // eslint-disable-line no-unused-vars

/**
* Length in ms for a touch to become a long press.
* @const
Expand Down Expand Up @@ -95,17 +108,20 @@ let longPid_ = 0;
const longStart = function(e, gesture) {
longStop();
// Punt on multitouch events.
if (e.changedTouches && e.changedTouches.length !== 1) {
if (e instanceof TouchEvent && e.changedTouches &&
e.changedTouches.length !== 1) {
return;
}
longPid_ = setTimeout(function() {
// TODO(#6097): Make types accurate, possibly by refactoring touch handling.
const typelessEvent = /** @type {?} */ (e);
// Additional check to distinguish between touch events and pointer events
if (e.changedTouches) {
if (typelessEvent.changedTouches) {
// TouchEvent
e.button = 2; // Simulate a right button click.
typelessEvent.button = 2; // Simulate a right button click.
// e was a touch event. It needs to pretend to be a mouse event.
e.clientX = e.changedTouches[0].clientX;
e.clientY = e.changedTouches[0].clientY;
typelessEvent.clientX = typelessEvent.changedTouches[0].clientX;
typelessEvent.clientY = typelessEvent.changedTouches[0].clientY;
}

// Let the gesture route the right-click correctly.
Expand Down Expand Up @@ -145,7 +161,7 @@ exports.clearTouchIdentifier = clearTouchIdentifier;
* Decide whether Blockly should handle or ignore this event.
* Mouse and touch events require special checks because we only want to deal
* with one touch stream at a time. All other events should always be handled.
* @param {!Event} e The event to check.
* @param {!(Event|PseudoEvent)} e The event to check.
* @return {boolean} True if this event should be passed through to the
* registered handler; false if it should be blocked.
* @alias Blockly.Touch.shouldHandleEvent
Expand All @@ -158,18 +174,31 @@ exports.shouldHandleEvent = shouldHandleEvent;
/**
* Get the touch identifier from the given event. If it was a mouse event, the
* identifier is the string 'mouse'.
* @param {!Event} e Mouse event or touch event.
* @param {!(Event|PseudoEvent)} e Mouse event or touch event.
* @return {string} The touch identifier from the first changed touch, if
* defined. Otherwise 'mouse'.
* @alias Blockly.Touch.getTouchIdentifierFromEvent
*/
const getTouchIdentifierFromEvent = function(e) {
return e.pointerId !== undefined ? e.pointerId :
(e.changedTouches && e.changedTouches[0] &&
e.changedTouches[0].identifier !== undefined &&
e.changedTouches[0].identifier !== null) ?
e.changedTouches[0].identifier :
'mouse';
if (e instanceof MouseEvent) {
return 'mouse';
}

if (e instanceof PointerEvent) {
return String(e.pointerId);
}

/**
* TODO(#6097): Fix types. This is a catch-all for everything but mouse
* and pointer events.
*/
const pseudoEvent = /** {!PseudoEvent} */ (e);

return (pseudoEvent.changedTouches && pseudoEvent.changedTouches[0] &&
pseudoEvent.changedTouches[0].identifier !== undefined &&
pseudoEvent.changedTouches[0].identifier !== null) ?
String(pseudoEvent.changedTouches[0].identifier) :
'mouse';
};
exports.getTouchIdentifierFromEvent = getTouchIdentifierFromEvent;

Expand All @@ -181,7 +210,7 @@ exports.getTouchIdentifierFromEvent = getTouchIdentifierFromEvent;
* If the current identifier was unset, save the identifier from the
* event. This starts a drag/gesture, during which touch events with other
* identifiers will be silently ignored.
* @param {!Event} e Mouse event or touch event.
* @param {!(Event|PseudoEvent)} e Mouse event or touch event.
* @return {boolean} Whether the identifier on the event matches the current
* saved identifier.
* @alias Blockly.Touch.checkTouchIdentifier
Expand Down Expand Up @@ -213,7 +242,7 @@ exports.checkTouchIdentifier = checkTouchIdentifier;
/**
* Set an event's clientX and clientY from its first changed touch. Use this to
* make a touch event work in a mouse event handler.
* @param {!Event} e A touch event.
* @param {!(Event|PseudoEvent)} e A touch event.
* @alias Blockly.Touch.setClientFromTouch
*/
const setClientFromTouch = function(e) {
Expand All @@ -227,9 +256,10 @@ const setClientFromTouch = function(e) {
exports.setClientFromTouch = setClientFromTouch;

/**
* Check whether a given event is a mouse or touch event.
* @param {!Event} e An event.
* @return {boolean} True if it is a mouse or touch event; false otherwise.
* Check whether a given event is a mouse, touch, or pointer event.
* @param {!(Event|PseudoEvent)} e An event.
* @return {boolean} True if it is a mouse, touch, or pointer event; false
* otherwise.
* @alias Blockly.Touch.isMouseOrTouchEvent
*/
const isMouseOrTouchEvent = function(e) {
Expand All @@ -241,8 +271,8 @@ exports.isMouseOrTouchEvent = isMouseOrTouchEvent;

/**
* Check whether a given event is a touch event or a pointer event.
* @param {!Event} e An event.
* @return {boolean} True if it is a touch event; false otherwise.
* @param {!(Event|PseudoEvent)} e An event.
* @return {boolean} True if it is a touch or pointer event; false otherwise.
* @alias Blockly.Touch.isTouchEvent
*/
const isTouchEvent = function(e) {
Expand All @@ -251,18 +281,20 @@ const isTouchEvent = function(e) {
};
exports.isTouchEvent = isTouchEvent;


/**
* Split an event into an array of events, one per changed touch or mouse
* point.
* @param {!Event} e A mouse event or a touch event with one or more changed
* touches.
* @return {!Array<!Event>} An array of mouse or touch events. Each touch
* event will have exactly one changed touch.
* @return {!Array<!(Event|PseudoEvent)>} An array of events or pseudo events.
* Each pseudo-touch event will have exactly one changed touch and there
* will be no real touch events.
* @alias Blockly.Touch.splitEventByTouches
*/
const splitEventByTouches = function(e) {
const events = [];
if (e.changedTouches) {
if (e instanceof TouchEvent) {
for (let i = 0; i < e.changedTouches.length; i++) {
const newEvent = {
type: e.type,
Expand Down
8 changes: 6 additions & 2 deletions core/touch_gesture.js
Original file line number Diff line number Diff line change
Expand Up @@ -324,9 +324,13 @@ class TouchGesture extends Gesture {
if (!this.startWorkspace_) {
return null;
}
// TODO(#6097): Make types accurate, possibly by refactoring touch handling.
const typelessEvent = /** @type {?} */ (e);
return new Coordinate(
(e.changedTouches ? e.changedTouches[0].pageX : e.pageX),
(e.changedTouches ? e.changedTouches[0].pageY : e.pageY));
(typelessEvent.changedTouches ? typelessEvent.changedTouches[0].pageX :
typelessEvent.pageX),
(typelessEvent.changedTouches ? typelessEvent.changedTouches[0].pageY :
typelessEvent.pageY));
}
}

Expand Down