import { PageFlip } from '../PageFlip' ; import { Point } from '../BasicTypes' ; import { FlipSetting , SizeType } from '../Settings' ; import { FlipCorner , FlippingState } from '../Flip/Flip' ; import { Orientation } from '../Render/Render' ; type SwipeData = { point : Point ; time : number ; } ; /**
 * UI Class, represents work with DOM
 */ export abstract class UI { protected readonly parentElement : HTMLElement ; protected readonly app : PageFlip ; protected readonly wrapper : HTMLElement ; protected distElement : HTMLElement ; private touchPoint : SwipeData = null ; private readonly swipeTimeout = 250 ; private readonly swipeDistance : number ; private onResize = ( ) : void => { this . update ( ) ; } ; constructor param { HTMLElement } inBlock param { PageFlip } app param { FlipSetting } setting protected constructor ( inBlock , app , setting ) { this . parentElement = inBlock ; inBlock . classList . add ( 'stf__parent' ) ; inBlock . insertAdjacentHTML ( 'afterbegin' , '<div class="stf__wrapper"></div>' ) ; this . wrapper = inBlock . querySelector ( '.stf__wrapper' ) ; this . app = app ; const k = this . app . getSettings ( ) . usePortrait ? 1 : 2 ; inBlock . style . minWidth = setting . minWidth * k + 'px' ; inBlock . style . minHeight = setting . minHeight + 'px' ; if ( setting . size === SizeType . FIXED ) { inBlock . style . minWidth = setting . width * k + 'px' ; inBlock . style . minHeight = setting . height + 'px' ; } if ( setting . autoSize ) { inBlock . style . width = '100%' ; inBlock . style . maxWidth = setting . maxWidth * 2 + 'px' ; } inBlock . style . display = 'block' ; window . addEventListener ( 'resize' , this . onResize , false ) ; this . swipeDistance = setting . swipeDistance ; } /**
     * Destructor. Remove all HTML elements and all event handlers
     */ public destroy ( ) { if ( this . app . getSettings ( ) . useMouseEvents ) this . removeHandlers ( ) ; this . distElement . remove ( ) ; this . wrapper . remove ( ) ; } /**
     * Updating child components when resizing
     */ public abstract update ( ) ; returns { HTMLElement } public getDistElement ( ) { return this . distElement ; } returns { HTMLElement } public getWrapper ( ) { return this . wrapper ; } param { Orientation } orientation public setOrientationStyle ( orientation ) { this . wrapper . classList . remove ( '--portrait' , '--landscape' ) ; if ( orientation === Orientation . PORTRAIT ) { if ( this . app . getSettings ( ) . autoSize ) this . wrapper . style . paddingBottom = ( this . app . getSettings ( ) . height / this . app . getSettings ( ) . width ) * 100 + '%' ; this . wrapper . classList . add ( '--portrait' ) ; } else { if ( this . app . getSettings ( ) . autoSize ) this . wrapper . style . paddingBottom = ( this . app . getSettings ( ) . height / ( this . app . getSettings ( ) . width * 2 ) ) * 100 + '%' ; this . wrapper . classList . add ( '--landscape' ) ; } this . update ( ) ; } protected removeHandlers ( ) { window . removeEventListener ( 'resize' , this . onResize ) ; this . distElement . removeEventListener ( 'mousedown' , this . onMouseDown ) ; this . distElement . removeEventListener ( 'touchstart' , this . onTouchStart ) ; window . removeEventListener ( 'mousemove' , this . onMouseMove ) ; window . removeEventListener ( 'touchmove' , this . onTouchMove ) ; window . removeEventListener ( 'mouseup' , this . onMouseUp ) ; window . removeEventListener ( 'touchend' , this . onTouchEnd ) ; } protected setHandlers ( ) { window . addEventListener ( 'resize' , this . onResize , false ) ; if ( ! this . app . getSettings ( ) . useMouseEvents ) return ; this . distElement . addEventListener ( 'mousedown' , this . onMouseDown ) ; this . distElement . addEventListener ( 'touchstart' , this . onTouchStart ) ; window . addEventListener ( 'mousemove' , this . onMouseMove ) ; window . addEventListener ( 'touchmove' , this . onTouchMove , { passive : ! this . app . getSettings ( ) . mobileScrollSupport , } ) ; window . addEventListener ( 'mouseup' , this . onMouseUp ) ; window . addEventListener ( 'touchend' , this . onTouchEnd ) ; } param x param y private getMousePos ( x , y ) { const rect = this . distElement . getBoundingClientRect ( ) ; return { x : x - rect . left , y : y - rect . top , } ; } private checkTarget ( targer ) { if ( ! this . app . getSettings ( ) . clickEventForward ) return true ; if ( [ 'a' , 'button' ] . includes ( ( targer as HTMLElement ) . tagName . toLowerCase ( ) ) ) { return false ; } return true ; } private onMouseDown = ( e ) : void => { if ( this . checkTarget ( e . target ) ) { const pos = this . getMousePos ( e . clientX , e . clientY ) ; this . app . startUserTouch ( pos ) ; e . preventDefault ( ) ; } } ; private onTouchStart = ( e ) : void => { if ( this . checkTarget ( e . target ) ) { if ( e . changedTouches . length > 0 ) { const t = e . changedTouches [ 0 ] ; const pos = this . getMousePos ( t . clientX , t . clientY ) ; this . touchPoint = { point : pos , time : Date . now ( ) , } ; setTimeout ( ( ) => { if ( this . touchPoint !== null ) { this . app . startUserTouch ( pos ) ; } } , this . swipeTimeout ) ; if ( ! this . app . getSettings ( ) . mobileScrollSupport ) e . preventDefault ( ) ; } } } ; private onMouseUp = ( e ) : void => { const pos = this . getMousePos ( e . clientX , e . clientY ) ; this . app . userStop ( pos ) ; } ; private onMouseMove = ( e ) : void => { const pos = this . getMousePos ( e . clientX , e . clientY ) ; this . app . userMove ( pos , false ) ; } ; private onTouchMove = ( e ) : void => { if ( e . changedTouches . length > 0 ) { const t = e . changedTouches [ 0 ] ; const pos = this . getMousePos ( t . clientX , t . clientY ) ; if ( this . app . getSettings ( ) . mobileScrollSupport ) { if ( this . touchPoint !== null ) { if ( Math . abs ( this . touchPoint . point . x - pos . x ) > 10 || this . app . getState ( ) !== FlippingState . READ ) { if ( e . cancelable ) this . app . userMove ( pos , true ) ; } } if ( this . app . getState ( ) !== FlippingState . READ ) { e . preventDefault ( ) ; } } else { this . app . userMove ( pos , true ) ; } } } ; private onTouchEnd = ( e ) : void => { if ( e . changedTouches . length > 0 ) { const t = e . changedTouches [ 0 ] ; const pos = this . getMousePos ( t . clientX , t . clientY ) ; let isSwipe = false ; if ( this . touchPoint !== null ) { const dx = pos . x - this . touchPoint . point . x ; const distY = Math . abs ( pos . y - this . touchPoint . point . y ) ; if ( Math . abs ( dx ) > this . swipeDistance && distY < this . swipeDistance * 2 && Date . now ( ) - this . touchPoint . time < this . swipeTimeout ) { if ( dx > 0 ) { this . app . flipPrev ( this . touchPoint . point . y < this . app . getRender ( ) . getRect ( ) . height / 2 ? FlipCorner . TOP : FlipCorner . BOTTOM ) ; } else { this . app . flipNext ( this . touchPoint . point . y < this . app . getRender ( ) . getRect ( ) . height / 2 ? FlipCorner . TOP : FlipCorner . BOTTOM ) ; } isSwipe = true ; } this . touchPoint = null ; } this . app . userStop ( pos , isSwipe ) ; } } ; }