Skip to content

Commit

Permalink
feat: add handling for native touch events
Browse files Browse the repository at this point in the history
fixes #6478
fixes #6381
fixes #6897
  • Loading branch information
nolimits4web committed Sep 28, 2023
1 parent 771ff52 commit 74bb1cc
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 34 deletions.
3 changes: 2 additions & 1 deletion src/core/core.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,8 @@ class Swiper {
velocities: [],
allowMomentumBounce: undefined,
startMoving: undefined,
evCache: [],
pointerId: null,
touchId: null,
},

// Clicks
Expand Down
4 changes: 4 additions & 0 deletions src/core/events/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,14 @@ const events = (swiper, method) => {
const swiperMethod = method;

// Touch Events
el[domMethod]('touchstart', swiper.onTouchStart, { passive: false });
el[domMethod]('pointerdown', swiper.onTouchStart, { passive: false });
document[domMethod]('touchmove', swiper.onTouchMove, { passive: false, capture });
document[domMethod]('pointermove', swiper.onTouchMove, { passive: false, capture });
document[domMethod]('touchend', swiper.onTouchEnd, { passive: true });
document[domMethod]('pointerup', swiper.onTouchEnd, { passive: true });
document[domMethod]('pointercancel', swiper.onTouchEnd, { passive: true });
document[domMethod]('touchcancel', swiper.onTouchEnd, { passive: true });
document[domMethod]('pointerout', swiper.onTouchEnd, { passive: true });
document[domMethod]('pointerleave', swiper.onTouchEnd, { passive: true });
document[domMethod]('contextmenu', swiper.onTouchEnd, { passive: true });
Expand Down
26 changes: 18 additions & 8 deletions src/core/events/onTouchEnd.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,25 @@ import { now, nextTick } from '../../shared/utils.mjs';
export default function onTouchEnd(event) {
const swiper = this;
const data = swiper.touchEventsData;
const pointerIndex = data.evCache.findIndex((cachedEv) => cachedEv.pointerId === event.pointerId);
if (pointerIndex >= 0) {
data.evCache.splice(pointerIndex, 1);

let e = event;
if (e.originalEvent) e = e.originalEvent;
let targetTouch;
const isTouchEvent = e.type === 'touchend' || e.type === 'touchcancel';
if (!isTouchEvent) {
if (data.touchId !== null) return; // return from pointer if we use touch
if (e.pointerId !== data.pointerId) return;
targetTouch = e;
} else {
targetTouch = [...e.changedTouches].filter((t) => t.identifier === data.touchId)[0];
if (!targetTouch || targetTouch.identifier !== data.touchId) return;
}
if (['pointercancel', 'pointerout', 'pointerleave', 'contextmenu'].includes(event.type)) {

data.pointerId = null;
data.touchId = null;
if (['pointercancel', 'pointerout', 'pointerleave', 'contextmenu'].includes(e.type)) {
const proceed =
['pointercancel', 'contextmenu'].includes(event.type) &&
['pointercancel', 'contextmenu'].includes(e.type) &&
(swiper.browser.isSafari || swiper.browser.isWebView);
if (!proceed) {
return;
Expand All @@ -18,10 +30,8 @@ export default function onTouchEnd(event) {

const { params, touches, rtlTranslate: rtl, slidesGrid, enabled } = swiper;
if (!enabled) return;
if (!params.simulateTouch && event.pointerType === 'mouse') return;
if (!params.simulateTouch && e.pointerType === 'mouse') return;

let e = event;
if (e.originalEvent) e = e.originalEvent;
if (data.allowTouchCallbacks) {
swiper.emit('touchEnd', e);
}
Expand Down
22 changes: 15 additions & 7 deletions src/core/events/onTouchMove.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,27 @@ export default function onTouchMove(event) {

let e = event;
if (e.originalEvent) e = e.originalEvent;

if (e.type === 'pointermove') {
if (data.touchId !== null) return; // return from pointer if we use touch
const id = e.pointerId;
if (id !== data.pointerId) return;
}
let targetTouch;
if (e.type === 'touchmove') {
targetTouch = [...e.changedTouches].filter((t) => t.identifier === data.touchId)[0];
if (!targetTouch || targetTouch.identifier !== data.touchId) return;
} else {
targetTouch = e;
}

if (!data.isTouched) {
if (data.startMoving && data.isScrolling) {
swiper.emit('touchMoveOpposite', e);
}
return;
}

const pointerIndex = data.evCache.findIndex((cachedEv) => cachedEv.pointerId === e.pointerId);
if (pointerIndex >= 0) data.evCache[pointerIndex] = e;
const targetTouch = data.evCache.length > 1 ? data.evCache[0] : e;
const pageX = targetTouch.pageX;
const pageY = targetTouch.pageY;

Expand Down Expand Up @@ -109,10 +120,7 @@ export default function onTouchMove(event) {
data.startMoving = true;
}
}
if (
data.isScrolling ||
(swiper.zoom && swiper.params.zoom && swiper.params.zoom.enabled && data.evCache.length > 1)
) {
if (data.isScrolling || (swiper.zoom && swiper.params.zoom && swiper.params.zoom.enabled)) {
data.isTouched = false;
return;
}
Expand Down
57 changes: 39 additions & 18 deletions src/core/events/onTouchStart.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,55 @@ function closestElement(selector, base = this) {
return __closestFrom(base);
}

function preventEdgeSwipe(swiper, event, startX) {
const window = getWindow();
const { params } = swiper;
const edgeSwipeDetection = params.edgeSwipeDetection;
const edgeSwipeThreshold = params.edgeSwipeThreshold;
if (
edgeSwipeDetection &&
(startX <= edgeSwipeThreshold || startX >= window.innerWidth - edgeSwipeThreshold)
) {
if (edgeSwipeDetection === 'prevent') {
event.preventDefault();
return true;
}
return false;
}
return true;
}

export default function onTouchStart(event) {
const swiper = this;
const document = getDocument();
const window = getWindow();

let e = event;
if (e.originalEvent) e = e.originalEvent;
const data = swiper.touchEventsData;
data.evCache.push(event);
if (e.type === 'pointerdown') {
if (data.pointerId !== null && data.pointerId !== e.pointerId) {
return;
}
data.pointerId = e.pointerId;
} else if (e.type === 'touchstart' && e.targetTouches.length === 1) {
data.touchId = e.targetTouches[0].identifier;
}
if (e.type === 'touchstart') {
// don't proceed touch event
preventEdgeSwipe(swiper, e, e.targetTouches[0].pageX);
return;
}

const { params, touches, enabled } = swiper;
if (!enabled) return;
if (!params.simulateTouch && event.pointerType === 'mouse') return;
if (!params.simulateTouch && e.pointerType === 'mouse') return;

if (swiper.animating && params.preventInteractionOnTransition) {
return;
}
if (!swiper.animating && params.cssMode && params.loop) {
swiper.loopFix();
}
let e = event;
if (e.originalEvent) e = e.originalEvent;

let targetEl = e.target;

if (params.touchEventsTarget === 'wrapper') {
Expand All @@ -46,7 +76,7 @@ export default function onTouchStart(event) {
// change target el for shadow root component
const swipingClassHasValue = !!params.noSwipingClass && params.noSwipingClass !== '';
// eslint-disable-next-line
const eventPath = event.composedPath ? event.composedPath() : event.path;
const eventPath = e.composedPath ? e.composedPath() : e.path;
if (swipingClassHasValue && e.target && e.target.shadowRoot && eventPath) {
targetEl = eventPath[0];
}
Expand Down Expand Up @@ -78,17 +108,8 @@ export default function onTouchStart(event) {

// Do NOT start if iOS edge swipe is detected. Otherwise iOS app cannot swipe-to-go-back anymore

const edgeSwipeDetection = params.edgeSwipeDetection || params.iOSEdgeSwipeDetection;
const edgeSwipeThreshold = params.edgeSwipeThreshold || params.iOSEdgeSwipeThreshold;
if (
edgeSwipeDetection &&
(startX <= edgeSwipeThreshold || startX >= window.innerWidth - edgeSwipeThreshold)
) {
if (edgeSwipeDetection === 'prevent') {
event.preventDefault();
} else {
return;
}
if (!preventEdgeSwipe(swiper, e, startX)) {
return;
}

Object.assign(data, {
Expand Down

0 comments on commit 74bb1cc

Please sign in to comment.