From c808fbb1ad0ef1f362d3e699653c66d782a306dc Mon Sep 17 00:00:00 2001 From: hadi Date: Thu, 1 Jun 2023 15:28:42 +0200 Subject: [PATCH] Fix swipe and popup contextmenu being triggered accidentally in touch devices --- api/js/egw_action/egw_action_popup.js | 2 +- api/js/etemplate/et2_dataview_view_aoi.ts | 4 +- api/js/tapandswipe.ts | 67 ++++++++++++++--------- calendar/js/app.ts | 2 +- 4 files changed, 45 insertions(+), 30 deletions(-) diff --git a/api/js/egw_action/egw_action_popup.js b/api/js/egw_action/egw_action_popup.js index 29b62f2291..8a76be4111 100644 --- a/api/js/egw_action/egw_action_popup.js +++ b/api/js/egw_action/egw_action_popup.js @@ -290,7 +290,7 @@ export function egwPopupActionImplementation() let tap = new tapAndSwipe(_node, { // this threshold must be the same as the one set in et2_dataview_view_aoi - tapHoldThreshold: 600, + tapHoldThreshold: 1000, allowScrolling: "both", tapAndHold: function(event, fingercount) { diff --git a/api/js/etemplate/et2_dataview_view_aoi.ts b/api/js/etemplate/et2_dataview_view_aoi.ts index 4b625a1696..f052e26b0b 100644 --- a/api/js/etemplate/et2_dataview_view_aoi.ts +++ b/api/js/etemplate/et2_dataview_view_aoi.ts @@ -117,10 +117,10 @@ export function et2_dataview_rowAOI(_node) if (egwIsMobile()) { let swipe = new tapAndSwipe(_node,{ // set the same threshold as action_popup event to get the tapAndHold working - tapHoldThreshold: 600, + tapHoldThreshold: 1000, swipe: function (event, direction, distance) { - if (distance > 100) selectHandler(event, {swip:direction}); + selectHandler(event, {swip:direction}); }, tap: function (event) { diff --git a/api/js/tapandswipe.ts b/api/js/tapandswipe.ts index dd3137a80f..2f073e3ef1 100644 --- a/api/js/tapandswipe.ts +++ b/api/js/tapandswipe.ts @@ -11,7 +11,7 @@ export interface TapAndSwipeOptions { // allow scrolling would stop swipe/tap events from being fired when there's scrolling available. It can be restricted // to Vertical/Horizental/Both scrolling. If no value set it means not allowed. allowScrolling? : string|null, - // tolorated pixel to fire the swipe events + // tolorated pixel for tap event threshold? : number, // time delay for defirentiate between tap event and long tap event, threshold is in milliseconds tapHoldThreshold? : number, @@ -23,6 +23,8 @@ export interface TapAndSwipeOptions { tap? : Function, // callback function being called on long tap(tap and hold) tapAndHold? : Function, + // tolerate pixel to fire swipe events + minSwipeThreshold? : number, } export type TapAndSwipeOptionsType = TapAndSwipeOptions; @@ -31,6 +33,7 @@ export class tapAndSwipe { static readonly _default : TapAndSwipeOptionsType = { threshold : 5, tapHoldThreshold : 3000, + minSwipeThreshold: 150, allowScrolling : 'both', swipe : function(){}, tap : function(){}, @@ -57,10 +60,17 @@ export class tapAndSwipe { */ private _endY : number = null; /** - * keeps the distance travelled between start point and end point + * keeps the distance travelled between startX point and endX point * @private */ - private _distance : number = null; + private _distanceX : number = null; + + /** + * keeps the distance travelled between startY point and endY point + * @private + */ + private _distanceY : number = null; + /** * flag to keep the status of type of tap * @private @@ -86,6 +96,9 @@ export class tapAndSwipe { private _hasBeenScrolled : boolean = false; private _scrollEventTriggered : boolean = false; + + private _stillMoving : boolean = false; + /** * Options * @protected @@ -131,7 +144,7 @@ export class tapAndSwipe { _onTouchMove(event) { - + this._stillMoving = true; } /** * on touch start event handler @@ -140,8 +153,8 @@ export class tapAndSwipe { */ private _onTouchStart(event : TouchEvent) { - this._startX = event.changedTouches[0].screenX; - this._startY = event.changedTouches[0].screenY; + this._startX = event.changedTouches[0].pageX; + this._startY = event.changedTouches[0].pageY; this._isTapAndHold = false; this._fingercount = event.touches.length; @@ -165,7 +178,7 @@ export class tapAndSwipe { this._tapHoldTimeout = window.setTimeout(_=>{ this._isTapAndHold = true; //check scrolling - if (this.options.allowScrolling && this._hasBeenScrolled) + if (this.options.allowScrolling && this._stillMoving) { return; } @@ -181,8 +194,9 @@ export class tapAndSwipe { */ private _ontouchEnd(event : TouchEvent) { - this._endX = event.changedTouches[0].screenX; - this._endY = event.changedTouches[0].screenY; + this._endX = event.changedTouches[0].pageX; + this._endY = event.changedTouches[0].pageY; + this._stillMoving = false; if (this._scrolledElementObj) { switch (this.options.allowScrolling) @@ -218,10 +232,13 @@ export class tapAndSwipe { { //cleanup tapHoldTimeout window.clearTimeout(this._tapHoldTimeout); + this._distanceX = Math.abs(this._endX-this._startX); + this._distanceY = Math.abs(this._endY-this._startY); const isTabOrHold = (this._endX == this._startX && this._endY == this._startY - || (Math.sqrt((this._endX-this._startX)*(this._endX-this._startX) + (this._endY-this._startY)+(this._endY-this._startY)) + || (Math.sqrt((this._distanceX)*(this._distanceX) + (this._distanceY*2)) < this.options.threshold)); + this._hasBeenScrolled = this._hasBeenScrolled ?? (!isTabOrHold && this._scrollEventTriggered); //check scrolling if (this.options.allowScrolling && this._hasBeenScrolled) @@ -231,13 +248,11 @@ export class tapAndSwipe { } // Tap & TapAndHold handler - if (this._endX == this._startX && this._endY == this._startY - || (Math.sqrt((this._endX-this._startX)*(this._endX-this._startX) + (this._endY-this._startY)+(this._endY-this._startY)) - < this.options.threshold)) + if (isTabOrHold) { if (!this._isTapAndHold) { - this._tapHoldTimeout = window.setTimeout(_=> { + this._tapTimeout = window.setTimeout(_=> { this.options.tap.call(this,event, this._fingercount); }, 100); } @@ -246,30 +261,30 @@ export class tapAndSwipe { } // left swipe handler - if (this._endX + this.options.threshold < this._startX) { - this._distance = this._startX - this._endX; - this.options.swipe.call(this, event, 'left', this._distance, this._fingercount); + if (this._endX + this.options.threshold < this._startX && this._distanceX > this._distanceY) { + if (this._distanceX < this.options.minSwipeThreshold) return; + this.options.swipe.call(this, event, 'left', this._distanceX, this._fingercount); return; } // right swipe handler - if (this._endX - this.options.threshold > this._startX) { - this._distance = this._endX - this._startX; - this.options.swipe.call(this, event, 'right', this._distance, this._fingercount); + if (this._endX - this.options.threshold > this._startX && this._distanceX > this._distanceY) { + if (this._distanceX < this.options.minSwipeThreshold) return; + this.options.swipe.call(this, event, 'right', this._distanceX, this._fingercount); return; } // up swipe handler - if (this._endY + this.options.threshold < this._startY) { - this._distance = this._startY - this._endY; - this.options.swipe.call(this, event, 'up', this._distance, this._fingercount); + if (this._endY + this.options.threshold < this._startY && this._distanceY > this._distanceX) { + if (this._distanceY < this.options.minSwipeThreshold) return; + this.options.swipe.call(this, event, 'up', this._distanceY, this._fingercount); return; } // down swipe handler - if (this._endY - this.options.threshold > this._startY) { - this._distance = this._endY - this._startY; - this.options.swipe.call(this, event, 'down', this._distance, this._fingercount); + if (this._endY - this.options.threshold > this._startY && this._distanceY > this._distanceX) { + if (this._distanceY < this.options.minSwipeThreshold) return; + this.options.swipe.call(this, event, 'down', this._distanceY, this._fingercount); return; } } diff --git a/calendar/js/app.ts b/calendar/js/app.ts index cec5defecb..b4cc578e82 100644 --- a/calendar/js/app.ts +++ b/calendar/js/app.ts @@ -1287,7 +1287,7 @@ export class CalendarApp extends EgwApp scroll_animate.call(jQuery(event.target).closest('.calendar_calTimeGrid, .calendar_plannerWidget')[0], direction, delta); return false; }, - threshold: 100, + minSwipeThreshold: 100, allowScrolling: 'vertical' });