import { ChangeDetectionStrategy , Component , ContentChild , ContentChildren , ElementRef , EventEmitter , NgZone , Optional , Output , QueryList , Renderer , ViewEncapsulation , forwardRef } from '@angular/core' ; import { assert , swipeShouldReset } from '../../util/util' ; import { Item } from './item' ; import { List } from '../list/list' ; import { Platform } from '../../platform/platform' ; import { ItemOptions } from './item-options' ; const SWIPE_MARGIN = 30 ; const ELASTIC_FACTOR = 0.55 ; const ITEM_SIDE_FLAG_NONE = 0 ; const ITEM_SIDE_FLAG_LEFT = 1 << 0 ; const ITEM_SIDE_FLAG_RIGHT = 1 << 1 ; const ITEM_SIDE_FLAG_BOTH = ITEM_SIDE_FLAG_LEFT | ITEM_SIDE_FLAG_RIGHT ; const enum SlidingState { Disabled = 1 << 1 , Enabled = 1 << 2 , Right = 1 << 3 , Left = 1 << 4 , SwipeRight = 1 << 5 , SwipeLeft = 1 << 6 } name description usage demo see {@link /docs/components#lists List Component Docs} see {@link ../Item Item API Docs} see {@link ../../list/List List API Docs} @ Component ( { selector : 'ion-item-sliding' , template : `
    <ng-content select="ion-item,[ion-item]"></ng-content>
    <ng-content select="ion-item-options"></ng-content>
  ` , changeDetection : ChangeDetectionStrategy . OnPush , encapsulation : ViewEncapsulation . None } ) export class ItemSliding { private _openAmount : number = 0 ; private _startX : number = 0 ; private _optsWidthRightSide : number = 0 ; private _optsWidthLeftSide : number = 0 ; private _sides : number ; private _tmr : number = null ; private _leftOptions : ItemOptions ; private _rightOptions : ItemOptions ; private _optsDirty : boolean = true ; private _state : SlidingState = SlidingState . Disabled ; hidden @ ContentChild ( Item ) item : Item ; output @ Output ( ) ionDrag : EventEmitter < ItemSliding > = new EventEmitter < ItemSliding > ( ) ; constructor ( @ Optional ( ) list , private _plt , private _renderer , private _elementRef , private _zone ) { list && list . containsSlidingItem ( true ) ; _elementRef . nativeElement . $ionComponent = this ; this . setElementClass ( 'item-wrapper' , true ) ; } @ ContentChildren ( forwardRef ( ( ) => ItemOptions ) ) set _itemOptions ( itemOptions ) { let sides = 0 ; this . _leftOptions = this . _rightOptions = null ; for ( var item of itemOptions . toArray ( ) ) { if ( item . isRightSide ( ) ) { this . _rightOptions = item ; sides |= ITEM_SIDE_FLAG_RIGHT ; } else { this . _leftOptions = item ; sides |= ITEM_SIDE_FLAG_LEFT ; } } this . _optsDirty = true ; this . _sides = sides ; } hidden getOpenAmount ( ) { return this . _openAmount ; } hidden getSlidingPercent ( ) { const openAmount = this . _openAmount ; if ( openAmount > 0 ) { return openAmount / this . _optsWidthRightSide ; } else if ( openAmount < 0 ) { return openAmount / this . _optsWidthLeftSide ; } else { return 0 ; } } hidden startSliding ( startX ) { if ( this . _tmr ) { this . _plt . cancelTimeout ( this . _tmr ) ; this . _tmr = null ; } if ( this . _openAmount === 0 ) { this . _optsDirty = true ; this . _setState ( SlidingState . Enabled ) ; } this . _startX = startX + this . _openAmount ; this . item . setElementStyle ( this . _plt . Css . transition , 'none' ) ; } hidden moveSliding ( x ) { if ( this . _optsDirty ) { this . calculateOptsWidth ( ) ; return ; } let openAmount = ( this . _startX - x ) ; switch ( this . _sides ) { case ITEM_SIDE_FLAG_RIGHT : openAmount = Math . max ( 0 , openAmount ) ; break ; case ITEM_SIDE_FLAG_LEFT : openAmount = Math . min ( 0 , openAmount ) ; break ; case ITEM_SIDE_FLAG_BOTH : break ; case ITEM_SIDE_FLAG_NONE : return ; default : assert ( false , 'invalid ItemSideFlags value' ) ; break ; } if ( openAmount > this . _optsWidthRightSide ) { const optsWidth = this . _optsWidthRightSide ; openAmount = optsWidth + ( openAmount - optsWidth ) * ELASTIC_FACTOR ; } else if ( openAmount < - this . _optsWidthLeftSide ) { const optsWidth = - this . _optsWidthLeftSide ; openAmount = optsWidth + ( openAmount - optsWidth ) * ELASTIC_FACTOR ; } this . _setOpenAmount ( openAmount , false ) ; return openAmount ; } hidden endSliding ( velocity ) { let restingPoint = ( this . _openAmount > 0 ) ? this . _optsWidthRightSide : - this . _optsWidthLeftSide ; const isResetDirection = ( this . _openAmount > 0 ) === ! ( velocity < 0 ) ; const isMovingFast = Math . abs ( velocity ) > 0.3 ; const isOnCloseZone = Math . abs ( this . _openAmount ) < Math . abs ( restingPoint / 2 ) ; if ( swipeShouldReset ( isResetDirection , isMovingFast , isOnCloseZone ) ) { restingPoint = 0 ; } this . fireSwipeEvent ( ) ; this . _setOpenAmount ( restingPoint , true ) ; return restingPoint ; } hidden private fireSwipeEvent ( ) { if ( this . _state & SlidingState . SwipeRight ) { this . _zone . run ( ( ) => this . _rightOptions . ionSwipe . emit ( this ) ) ; } else if ( this . _state & SlidingState . SwipeLeft ) { this . _zone . run ( ( ) => this . _leftOptions . ionSwipe . emit ( this ) ) ; } } hidden private calculateOptsWidth ( ) { if ( ! this . _optsDirty ) { return ; } this . _optsWidthRightSide = 0 ; if ( this . _rightOptions ) { this . _optsWidthRightSide = this . _rightOptions . width ( ) ; assert ( this . _optsWidthRightSide > 0 , '_optsWidthRightSide should not be zero' ) ; } this . _optsWidthLeftSide = 0 ; if ( this . _leftOptions ) { this . _optsWidthLeftSide = this . _leftOptions . width ( ) ; assert ( this . _optsWidthLeftSide > 0 , '_optsWidthLeftSide should not be zero' ) ; } this . _optsDirty = false ; } private _setOpenAmount ( openAmount , isFinal ) { const platform = this . _plt ; if ( this . _tmr ) { platform . cancelTimeout ( this . _tmr ) ; this . _tmr = null ; } this . _openAmount = openAmount ; if ( isFinal ) { this . item . setElementStyle ( platform . Css . transition , '' ) ; } if ( openAmount > 0 ) { var state = ( openAmount >= ( this . _optsWidthRightSide + SWIPE_MARGIN ) ) ? SlidingState . Right | SlidingState . SwipeRight : SlidingState . Right ; this . _setState ( state ) ; } else if ( openAmount < 0 ) { const state = ( openAmount <= ( - this . _optsWidthLeftSide - SWIPE_MARGIN ) ) ? SlidingState . Left | SlidingState . SwipeLeft : SlidingState . Left ; this . _setState ( state ) ; } else { assert ( openAmount === 0 , 'bad internal state' ) ; this . _tmr = platform . timeout ( ( ) => { this . _setState ( SlidingState . Disabled ) ; this . _tmr = null ; } , 600 ) ; this . item . setElementStyle ( platform . Css . transform , '' ) ; return ; } this . item . setElementStyle ( platform . Css . transform , `translate3d(${ - openAmount }px,0,0)` ) ; const ionDrag = this . ionDrag ; if ( ionDrag . observers . length > 0 ) { ionDrag . emit ( this ) ; } } private _setState ( state ) { if ( state === this . _state ) { return ; } this . setElementClass ( 'active-slide' , ( state !== SlidingState . Disabled ) ) ; this . setElementClass ( 'active-options-right' , ! ! ( state & SlidingState . Right ) ) ; this . setElementClass ( 'active-options-left' , ! ! ( state & SlidingState . Left ) ) ; this . setElementClass ( 'active-swipe-right' , ! ! ( state & SlidingState . SwipeRight ) ) ; this . setElementClass ( 'active-swipe-left' , ! ! ( state & SlidingState . SwipeLeft ) ) ; this . _state = state ; } Component close ( ) { this . _setOpenAmount ( 0 , true ) ; } hidden setElementClass ( cssClass , shouldAdd ) { this . _renderer . setElementClass ( this . _elementRef . nativeElement , cssClass , shouldAdd ) ; } }