From 6b7965a727b578dde84cbd5fc9453b3a4479a231 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Wed, 20 Jul 2016 17:03:06 -0700 Subject: [PATCH] Ignore everything but the first touch stream --- core/block_svg.js | 3 ++- core/blockly.js | 42 +++++++++++++++++++++++++++++++++++++++--- core/field.js | 1 + core/flyout.js | 1 + core/scrollbar.js | 3 ++- core/utils.js | 35 ++++++++++++++++++++++++++++------- 6 files changed, 73 insertions(+), 12 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index af19bb4a1..08269a8f4 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -523,7 +523,7 @@ Blockly.BlockSvg.prototype.tab = function(start, forward) { /** * Handle a mouse-down on an SVG block. - * @param {!Event} e Mouse down event. + * @param {!Event} e Mouse down event or touch start event. * @private */ Blockly.BlockSvg.prototype.onMouseDown_ = function(e) { @@ -585,6 +585,7 @@ Blockly.BlockSvg.prototype.onMouseDown_ = function(e) { * @private */ Blockly.BlockSvg.prototype.onMouseUp_ = function(e) { + Blockly.touchIdentifier_ = null; if (Blockly.dragMode_ != Blockly.DRAG_FREE && !Blockly.WidgetDiv.isVisible()) { Blockly.Events.fire( diff --git a/core/blockly.js b/core/blockly.js index c01e94a25..3e533dc61 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -120,6 +120,12 @@ Blockly.dragMode_ = Blockly.DRAG_NONE; */ Blockly.onTouchUpWrapper_ = null; +/** + * Which touch events are we currently paying attention to? + * @type {?DOMString} + */ +Blockly.touchIdentifier_ = null; + /** * Convert a hue (HSV model) into an RGB hex triplet. * @param {number} hue Hue on a colour wheel (0-360). @@ -149,6 +155,38 @@ Blockly.resizeSvgContents = function(workspace) { workspace.resizeContents(); }; +/** + * Check whether the touch identifier on the event matches the current saved + * identifier. If there is no identifier, that means it's a mouse event and + * we'll use the identifier "mouse". This means we won't deal well with + * multiple mice being used at the same time. That seems okay. + * If the current identifier was unset, save the identifier from the + * event. + * @param {!Event} e Mouse event or touch event. + * @return {boolean} Whether the identifier on the event matches the current + * saved identifier. + */ +Blockly.checkTouchIdentifier = function(e) { + var identifier = (e.changedTouches && e.changedTouches.item(0) && + e.changedTouches.item(0).identifier != undefined) ? + e.changedTouches.item(0).identifier : "mouse"; + if (Blockly.touchIdentifier_ != null && + Blockly.touchIdentifier_ != undefined) { + // We're already tracking some touch/mouse event. Is this from the same + // source? + return Blockly.touchIdentifier_ == identifier; + } + if (e.type == "mousedown" || e.type == "touchstart") { + // No identifier set yet, and this is the start of a drag. Set it and + // return. + Blockly.touchIdentifier_ = identifier; + return true; + } + // There was no identifier yet, but this wasn't a start event so we're going + // to ignore it. This probably means that another drag finished while this + // pointer was down. + return false; +}; /** * Size the SVG image to completely fill its container. Call this when the view @@ -188,6 +226,7 @@ Blockly.svgResize = function(workspace) { * @private */ Blockly.onMouseUp_ = function(e) { + Blockly.touchIdentifier_ = null; var workspace = Blockly.getMainWorkspace(); Blockly.Css.setCursor(Blockly.Css.Cursor.OPEN); workspace.dragMode_ = Blockly.DRAG_NONE; @@ -208,9 +247,6 @@ Blockly.onMouseUp_ = function(e) { * @private */ Blockly.onMouseMove_ = function(e) { - if (e.touches && e.touches.length >= 2) { - return; // Multi-touch gestures won't have e.clientX. - } var workspace = Blockly.getMainWorkspace(); if (workspace.dragMode_ != Blockly.DRAG_NONE) { var dx = e.clientX - workspace.startDragMouseX; diff --git a/core/field.js b/core/field.js index 9060e8532..1d40b1e6b 100644 --- a/core/field.js +++ b/core/field.js @@ -460,6 +460,7 @@ Blockly.Field.prototype.setValue = function(newText) { * @private */ Blockly.Field.prototype.onMouseUp_ = function(e) { + Blockly.touchIdentifier_ = null; if ((goog.userAgent.IPHONE || goog.userAgent.IPAD) && !goog.userAgent.isVersionOrHigher('537.51.2') && e.layerX !== 0 && e.layerY !== 0) { diff --git a/core/flyout.js b/core/flyout.js index 0647b7219..53b57b7d8 100644 --- a/core/flyout.js +++ b/core/flyout.js @@ -791,6 +791,7 @@ Blockly.Flyout.prototype.onMouseDown_ = function(e) { * @private */ Blockly.Flyout.prototype.onMouseUp_ = function(e) { + Blockly.touchIdentifier_ = null; if (!this.workspace_.isDragging()) { if (this.autoClose) { this.createBlockFunc_(Blockly.Flyout.startBlock_)( diff --git a/core/scrollbar.js b/core/scrollbar.js index da2dd942d..c0f83f373 100644 --- a/core/scrollbar.js +++ b/core/scrollbar.js @@ -637,7 +637,7 @@ Blockly.Scrollbar.prototype.onMouseDownBar_ = function(e) { * @private */ Blockly.Scrollbar.prototype.onMouseDownHandle_ = function(e) { - this.onMouseUpHandle_(); + Blockly.hideChaff(true); if (Blockly.isRightButton(e)) { // Right-click. // Scrollbars have no context menu. @@ -675,6 +675,7 @@ Blockly.Scrollbar.prototype.onMouseMoveHandle_ = function(e) { * @private */ Blockly.Scrollbar.prototype.onMouseUpHandle_ = function() { + Blockly.touchIdentifier_ = null; Blockly.hideChaff(true); if (Blockly.Scrollbar.onMouseUpWrapper_) { Blockly.unbindEvent_(Blockly.Scrollbar.onMouseUpWrapper_); diff --git a/core/utils.js b/core/utils.js index fe13572ac..2656323eb 100644 --- a/core/utils.js +++ b/core/utils.js @@ -101,23 +101,30 @@ Blockly.hasClass_ = function(element, className) { Blockly.bindEvent_ = function(node, name, thisObject, func) { if (thisObject) { var wrapFunc = function(e) { + if (!Blockly.checkTouchIdentifier(e)) { + return; + } + Blockly.bindEvent_.setClientFromTouch(e); func.call(thisObject, e); }; } else { - var wrapFunc = func; + var wrapFunc = function(e) { + if (!Blockly.checkTouchIdentifier(e)) { + return; + } + Blockly.bindEvent_.setClientFromTouch(e); + func(e); + }; } node.addEventListener(name, wrapFunc, false); var bindData = [[node, name, wrapFunc]]; // Add equivalent touch event. if (name in Blockly.bindEvent_.TOUCH_MAP) { wrapFunc = function(e) { - // Punt on multitouch events. - if (e.changedTouches.length == 1) { - // Map the touch event's properties to the event. - var touchPoint = e.changedTouches[0]; - e.clientX = touchPoint.clientX; - e.clientY = touchPoint.clientY; + if (!Blockly.checkTouchIdentifier(e)) { + return; } + Blockly.bindEvent_.setClientFromTouch(e); func.call(thisObject, e); // Stop the browser from scrolling/zooming the page. e.preventDefault(); @@ -145,6 +152,20 @@ if (goog.events.BrowserFeature.TOUCH_ENABLED) { }; } +/** + * 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. + */ +Blockly.bindEvent_.setClientFromTouch = function(e) { + if (e.type.indexOf('touch') == 0) { + // Map the touch event's properties to the event. + var touchPoint = e.changedTouches[0]; + e.clientX = touchPoint.clientX; + e.clientY = touchPoint.clientY; + } +}; + /** * Unbind one or more events event from a function call. * @param {!Array.} bindData Opaque data from bindEvent_. This list is