break touch interaction into own module
This commit is contained in:
		| @@ -1,7 +1,5 @@ | ||||
| import { enterFullscreen } from '../utils/util.js' | ||||
|  | ||||
| /** | ||||
|  * Handles all reveal.js keyboard interactions. | ||||
|  * Reads and writes the URL based on reveal.js' current state. | ||||
|  */ | ||||
| export default class Location { | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,5 @@ | ||||
| import { enterFullscreen } from '../utils/util.js' | ||||
|  | ||||
| /** | ||||
|  * Handles all reveal.js keyboard interactions. | ||||
|  * Handles the display of reveal.js' optional slide number. | ||||
|  */ | ||||
| export default class SlideNumber { | ||||
|  | ||||
|   | ||||
							
								
								
									
										255
									
								
								js/controllers/touch.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										255
									
								
								js/controllers/touch.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,255 @@ | ||||
| const SWIPE_THRESHOLD = 40; | ||||
|  | ||||
| /** | ||||
|  * Controls all touch interactions and navigations for | ||||
|  * a presentation. | ||||
|  */ | ||||
| export default class Touch { | ||||
|  | ||||
| 	constructor( Reveal ) { | ||||
|  | ||||
| 		this.Reveal = Reveal; | ||||
|  | ||||
| 		// Holds information about the currently ongoing touch interaction | ||||
| 		this.touchStartX = 0; | ||||
| 		this.touchStartY = 0; | ||||
| 		this.touchStartCount = 0; | ||||
| 		this.touchCaptured = false; | ||||
|  | ||||
| 		this.onPointerDown = this.onPointerDown.bind( this ); | ||||
| 		this.onPointerMove = this.onPointerMove.bind( this ); | ||||
| 		this.onPointerUp = this.onPointerUp.bind( this ); | ||||
| 		this.onTouchStart = this.onTouchStart.bind( this ); | ||||
| 		this.onTouchMove = this.onTouchMove.bind( this ); | ||||
| 		this.onTouchEnd = this.onTouchEnd.bind( this ); | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * | ||||
| 	 */ | ||||
| 	bind() { | ||||
|  | ||||
| 		var revealElement = this.Reveal.getRevealElement(); | ||||
|  | ||||
| 		if( 'onpointerdown' in window ) { | ||||
| 			// Use W3C pointer events | ||||
| 			revealElement.addEventListener( 'pointerdown', this.onPointerDown, false ); | ||||
| 			revealElement.addEventListener( 'pointermove', this.onPointerMove, false ); | ||||
| 			revealElement.addEventListener( 'pointerup', this.onPointerUp, false ); | ||||
| 		} | ||||
| 		else if( window.navigator.msPointerEnabled ) { | ||||
| 			// IE 10 uses prefixed version of pointer events | ||||
| 			revealElement.addEventListener( 'MSPointerDown', this.onPointerDown, false ); | ||||
| 			revealElement.addEventListener( 'MSPointerMove', this.onPointerMove, false ); | ||||
| 			revealElement.addEventListener( 'MSPointerUp', this.onPointerUp, false ); | ||||
| 		} | ||||
| 		else { | ||||
| 			// Fall back to touch events | ||||
| 			revealElement.addEventListener( 'touchstart', this.onTouchStart, false ); | ||||
| 			revealElement.addEventListener( 'touchmove', this.onTouchMove, false ); | ||||
| 			revealElement.addEventListener( 'touchend', this.onTouchEnd, false ); | ||||
| 		} | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * | ||||
| 	 */ | ||||
| 	unbind() { | ||||
|  | ||||
| 		var revealElement = this.Reveal.getRevealElement(); | ||||
|  | ||||
| 		revealElement.removeEventListener( 'pointerdown', this.onPointerDown, false ); | ||||
| 		revealElement.removeEventListener( 'pointermove', this.onPointerMove, false ); | ||||
| 		revealElement.removeEventListener( 'pointerup', this.onPointerUp, false ); | ||||
|  | ||||
| 		revealElement.removeEventListener( 'MSPointerDown', this.onPointerDown, false ); | ||||
| 		revealElement.removeEventListener( 'MSPointerMove', this.onPointerMove, false ); | ||||
| 		revealElement.removeEventListener( 'MSPointerUp', this.onPointerUp, false ); | ||||
|  | ||||
| 		revealElement.removeEventListener( 'touchstart', this.onTouchStart, false ); | ||||
| 		revealElement.removeEventListener( 'touchmove', this.onTouchMove, false ); | ||||
| 		revealElement.removeEventListener( 'touchend', this.onTouchEnd, false ); | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Checks if the target element prevents the triggering of | ||||
| 	 * swipe navigation. | ||||
| 	 */ | ||||
| 	isSwipePrevented( target ) { | ||||
|  | ||||
| 		while( target && typeof target.hasAttribute === 'function' ) { | ||||
| 			if( target.hasAttribute( 'data-prevent-swipe' ) ) return true; | ||||
| 			target = target.parentNode; | ||||
| 		} | ||||
|  | ||||
| 		return false; | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Handler for the 'touchstart' event, enables support for | ||||
| 	 * swipe and pinch gestures. | ||||
| 	 * | ||||
| 	 * @param {object} event | ||||
| 	 */ | ||||
| 	onTouchStart( event ) { | ||||
|  | ||||
| 		if( this.isSwipePrevented( event.target ) ) return true; | ||||
|  | ||||
| 		this.touchStartX = event.touches[0].clientX; | ||||
| 		this.touchStartY = event.touches[0].clientY; | ||||
| 		this.touchStartCount = event.touches.length; | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Handler for the 'touchmove' event. | ||||
| 	 * | ||||
| 	 * @param {object} event | ||||
| 	 */ | ||||
| 	onTouchMove( event ) { | ||||
|  | ||||
| 		if( this.isSwipePrevented( event.target ) ) return true; | ||||
|  | ||||
| 		let config = this.Reveal.getConfig(); | ||||
|  | ||||
| 		// Each touch should only trigger one action | ||||
| 		if( !this.touchCaptured ) { | ||||
| 			this.Reveal.onUserInput( event ); | ||||
|  | ||||
| 			let currentX = event.touches[0].clientX; | ||||
| 			let currentY = event.touches[0].clientY; | ||||
|  | ||||
| 			// There was only one touch point, look for a swipe | ||||
| 			if( event.touches.length === 1 && this.touchStartCount !== 2 ) { | ||||
|  | ||||
| 				let deltaX = currentX - this.touchStartX, | ||||
| 					deltaY = currentY - this.touchStartY; | ||||
|  | ||||
| 				if( deltaX > SWIPE_THRESHOLD && Math.abs( deltaX ) > Math.abs( deltaY ) ) { | ||||
| 					this.touchCaptured = true; | ||||
| 					if( config.navigationMode === 'linear' ) { | ||||
| 						if( config.rtl ) { | ||||
| 							this.Reveal.next(); | ||||
| 						} | ||||
| 						else { | ||||
| 							this.Reveal.prev()(); | ||||
| 						} | ||||
| 					} | ||||
| 					else { | ||||
| 						this.Reveal.left(); | ||||
| 					} | ||||
| 				} | ||||
| 				else if( deltaX < -SWIPE_THRESHOLD && Math.abs( deltaX ) > Math.abs( deltaY ) ) { | ||||
| 					this.touchCaptured = true; | ||||
| 					if( config.navigationMode === 'linear' ) { | ||||
| 						if( config.rtl ) { | ||||
| 							this.Reveal.prev()(); | ||||
| 						} | ||||
| 						else { | ||||
| 							this.Reveal.next(); | ||||
| 						} | ||||
| 					} | ||||
| 					else { | ||||
| 						this.Reveal.right(); | ||||
| 					} | ||||
| 				} | ||||
| 				else if( deltaY > SWIPE_THRESHOLD ) { | ||||
| 					this.touchCaptured = true; | ||||
| 					if( config.navigationMode === 'linear' ) { | ||||
| 						this.Reveal.prev()(); | ||||
| 					} | ||||
| 					else { | ||||
| 						this.Reveal.up(); | ||||
| 					} | ||||
| 				} | ||||
| 				else if( deltaY < -SWIPE_THRESHOLD ) { | ||||
| 					this.touchCaptured = true; | ||||
| 					if( config.navigationMode === 'linear' ) { | ||||
| 						this.Reveal.next(); | ||||
| 					} | ||||
| 					else { | ||||
| 						this.Reveal.down(); | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 				// If we're embedded, only block touch events if they have | ||||
| 				// triggered an action | ||||
| 				if( config.embedded ) { | ||||
| 					if( this.touchCaptured || this.Reveal.isVerticalSlide( currentSlide ) ) { | ||||
| 						event.preventDefault(); | ||||
| 					} | ||||
| 				} | ||||
| 				// Not embedded? Block them all to avoid needless tossing | ||||
| 				// around of the viewport in iOS | ||||
| 				else { | ||||
| 					event.preventDefault(); | ||||
| 				} | ||||
|  | ||||
| 			} | ||||
| 		} | ||||
| 		// There's a bug with swiping on some Android devices unless | ||||
| 		// the default action is always prevented | ||||
| 		else if( isAndroid ) { | ||||
| 			event.preventDefault(); | ||||
| 		} | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Handler for the 'touchend' event. | ||||
| 	 * | ||||
| 	 * @param {object} event | ||||
| 	 */ | ||||
| 	onTouchEnd( event ) { | ||||
|  | ||||
| 		this.touchCaptured = false; | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Convert pointer down to touch start. | ||||
| 	 * | ||||
| 	 * @param {object} event | ||||
| 	 */ | ||||
| 	onPointerDown( event ) { | ||||
|  | ||||
| 		if( event.pointerType === event.MSPOINTER_TYPE_TOUCH || event.pointerType === "touch" ) { | ||||
| 			event.touches = [{ clientX: event.clientX, clientY: event.clientY }]; | ||||
| 			this.onTouchStart( event ); | ||||
| 		} | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Convert pointer move to touch move. | ||||
| 	 * | ||||
| 	 * @param {object} event | ||||
| 	 */ | ||||
| 	onPointerMove( event ) { | ||||
|  | ||||
| 		if( event.pointerType === event.MSPOINTER_TYPE_TOUCH || event.pointerType === "touch" )  { | ||||
| 			event.touches = [{ clientX: event.clientX, clientY: event.clientY }]; | ||||
| 			this.onTouchMove( event ); | ||||
| 		} | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Convert pointer up to touch end. | ||||
| 	 * | ||||
| 	 * @param {object} event | ||||
| 	 */ | ||||
| 	onPointerUp( event ) { | ||||
|  | ||||
| 		if( event.pointerType === event.MSPOINTER_TYPE_TOUCH || event.pointerType === "touch" )  { | ||||
| 			event.touches = [{ clientX: event.clientX, clientY: event.clientY }]; | ||||
| 			this.onTouchEnd( event ); | ||||
| 		} | ||||
|  | ||||
| 	} | ||||
|  | ||||
| } | ||||
		Reference in New Issue
	
	Block a user