import { Component , Input , OnDestroy , Output , EventEmitter , ElementRef , HostListener } from '@angular/core' ; import { isBs3 , LinkedList } from '../utils' ; import { SlideComponent } from './slide.component' ; import { CarouselConfig } from './carousel.config' ; export enum Direction { UNKNOWN , NEXT , PREV } /**
* Base element to create carousel
*/ @ Component ( { selector : 'mdb-carousel' , templateUrl : './carousel.component.html' , } ) export class CarouselComponent implements OnDestroy { SWIPE_ACTION = { LEFT : 'swipeleft' , RIGHT : 'swiperight' } ; protected _slides : LinkedList < SlideComponent > = new LinkedList < SlideComponent > ( ) ; public get slides ( ) : SlideComponent [ ] { return this . _slides . toArray ( ) ; } protected currentInterval : any ; protected isPlaying : boolean ; protected destroyed = false ; protected el : ElementRef | any = null ; protected animationEnd = true ; /** If `true` — carousel will not cycle continuously and will have hard stops (prevent looping) */ @ Input ( ) public noWrap : boolean ; /**  If `true` — will disable pausing on carousel mouse hover */ @ Input ( ) public noPause : boolean ; @ Input ( 'isControls' ) public isControls : boolean = true ; @ Input ( ) public keyboard : boolean ; @ Input ( 'class' ) public class : String = '' ; @ Input ( 'type' ) public type : String = '' ; @ Input ( 'animation' ) public animation : String = '' ; protected _currentActiveSlide : number | any ; /** Will be emitted when active slide has been changed. Part of two-way-bindable [(activeSlide)] property */ @ Output ( ) public activeSlideChange : EventEmitter < any > = new EventEmitter < any > ( false ) ; /** Index of currently displayed slide(started for 0) */ @ Input ( ) public set activeSlide ( index ) { if ( this . _slides . length && index !== this . _currentActiveSlide ) { this . _select ( index ) ; } } public get activeSlide ( ) : number { return this . _currentActiveSlide ; } protected _interval : number ; public checkNavigation ( ) { if ( this . type === 'carousel-multi-item' ) { return false ; } return true ; } public checkDots ( ) { if ( this . type === 'carousel-thumbnails' ) { return false ; } return true ; } getImg ( slide ) { return slide . el . nativeElement . querySelector ( 'img' ) . src ; } /**
     * Delay of item cycling in milliseconds. If false, carousel won't cycle automatically.
     */ @ Input ( ) public get interval ( ) : number { return this . _interval ; } public set interval ( value ) { this . _interval = value ; this . restartTimer ( ) ; } public get isBs4 ( ) : boolean { return ! isBs3 ( ) ; } public constructor ( config , el ) { Object . assign ( this , config ) ; this . el = el ; } public ngOnDestroy ( ) { this . destroyed = true ; } param slide public addSlide ( slide ) { this . _slides . add ( slide ) ; if ( this . _slides . length === 1 ) { this . _currentActiveSlide = void 0 ; this . activeSlide = 0 ; this . play ( ) ; } } param slide public removeSlide ( slide ) { const remIndex = this . _slides . indexOf ( slide ) ; if ( this . _currentActiveSlide === remIndex ) { let nextSlideIndex = void 0 ; if ( this . _slides . length > 1 ) { nextSlideIndex = ! this . isLast ( remIndex ) ? remIndex : this . noWrap ? remIndex - 1 : 0 ; } this . _slides . remove ( remIndex ) ; setTimeout ( ( ) => { this . _select ( nextSlideIndex ) ; } , 0 ) ; } else { this . _slides . remove ( remIndex ) ; const currentSlideIndex = this . getCurrentSlideIndex ( ) ; setTimeout ( ( ) => { this . _currentActiveSlide = currentSlideIndex ; this . activeSlideChange . emit ( this . _currentActiveSlide ) ; } , 0 ) ; } } swipe ( action = this . SWIPE_ACTION . RIGHT ) { if ( action === this . SWIPE_ACTION . RIGHT ) { this . previousSlide ( ) ; } if ( action === this . SWIPE_ACTION . LEFT ) { this . nextSlide ( ) ; } } param force public nextSlide ( force = false ) { if ( this . animation === 'slide' ) { this . pause ( ) ; const direction = Direction . NEXT ; this . slideAnimation ( this . findNextSlideIndex ( direction , force ) , direction ) ; } else if ( this . animation === 'fade' ) { this . pause ( ) ; this . fadeAnimation ( this . findNextSlideIndex ( Direction . NEXT , force ) ) ; } else { this . activeSlide = this . findNextSlideIndex ( Direction . NEXT , force ) ; } } param force public previousSlide ( force = false ) { if ( this . animation === 'slide' ) { this . pause ( ) ; const direction = Direction . PREV ; this . slideAnimation ( this . findNextSlideIndex ( direction , force ) , direction ) ; } else if ( this . animation === 'fade' ) { this . pause ( ) ; this . fadeAnimation ( this . findNextSlideIndex ( Direction . PREV , force ) ) ; } else { this . activeSlide = this . findNextSlideIndex ( Direction . PREV , force ) ; } } protected fadeAnimation ( goToIndex ) { const goToSlide = this . _slides . get ( goToIndex ) ; if ( this . animationEnd ) { this . animationEnd = false ; goToSlide . directionNext = true ; setTimeout ( ( ) => { goToSlide . directionNext = false ; this . animationEnd = true ; this . activeSlide = goToIndex ; this . play ( ) ; } , 100 ) ; } } protected slideAnimation ( goToIndex , direction ) { const currentSlide = this . _slides . get ( this . _currentActiveSlide ) ; const goToSlide = this . _slides . get ( goToIndex ) ; if ( this . animationEnd ) { if ( direction === Direction . NEXT ) { this . animationEnd = false ; goToSlide . directionNext = true ; setTimeout ( ( ) => { goToSlide . directionLeft = true ; currentSlide . directionLeft = true ; } , 100 ) ; } if ( direction === Direction . PREV ) { this . animationEnd = false ; goToSlide . directionPrev = true ; setTimeout ( ( ) => { goToSlide . directionRight = true ; currentSlide . directionRight = true ; } , 100 ) ; } setTimeout ( ( ) => { goToSlide . directionLeft = false ; goToSlide . directionNext = false ; currentSlide . directionLeft = false ; currentSlide . directionNext = false ; goToSlide . directionRight = false ; goToSlide . directionPrev = false ; currentSlide . directionRight = false ; currentSlide . directionPrev = false ; this . animationEnd = true ; this . activeSlide = goToIndex ; let directionName ; if ( direction === Direction . NEXT ) { directionName = 'Next' ; } else if ( direction === Direction . PREV ) { directionName = 'Prev' ; } this . activeSlideChange . emit ( { 'direction' : directionName , 'relatedTarget' : this . activeSlide } ) ; this . play ( ) ; } , 700 ) ; } } param index public selectSlide ( index ) { this . pause ( ) ; if ( this . animation === 'slide' ) { if ( this . activeSlide < index ) { this . slideAnimation ( index , Direction . NEXT ) ; } else if ( this . activeSlide > index ) { this . slideAnimation ( index , Direction . PREV ) ; } } else if ( this . animation === 'fade' ) { if ( index !== this . activeSlide ) { this . fadeAnimation ( index ) ; } } this . play ( ) ; } /**
     * Starts a auto changing of slides
     */ @ HostListener ( 'mouseleave' ) play ( ) { if ( ! this . isPlaying ) { this . isPlaying = true ; this . restartTimer ( ) ; } } /**
     * Stops a auto changing of slides
     */ @ HostListener ( 'mouseenter' ) pause ( ) { if ( ! this . noPause ) { this . isPlaying = false ; this . resetTimer ( ) ; } } returns { number } public getCurrentSlideIndex ( ) { return this . _slides . findIndex ( ( slide ) => slide . active ) ; } param index returns { boolean } public isLast ( index ) { return index + 1 >= this . _slides . length ; } param direction param force returns { any } private findNextSlideIndex ( direction , force ) { let nextSlideIndex = 0 ; if ( ! force && ( this . isLast ( this . activeSlide ) && direction !== Direction . PREV && this . noWrap ) ) { return void 0 ; } switch ( direction ) { case Direction . NEXT : nextSlideIndex = ( ! this . isLast ( this . _currentActiveSlide ) ) ? this . _currentActiveSlide + 1 : ( ! force && this . noWrap ) ? this . _currentActiveSlide : 0 ; break ; case Direction . PREV : nextSlideIndex = ( this . _currentActiveSlide > 0 ) ? this . _currentActiveSlide - 1 : ( ! force && this . noWrap ) ? this . _currentActiveSlide : this . _slides . length - 1 ; break ; default : throw new Error ( 'Unknown direction' ) ; } return nextSlideIndex ; } param index private private _select ( index ) { if ( isNaN ( index ) ) { this . pause ( ) ; return ; } const currentSlide = this . _slides . get ( this . _currentActiveSlide ) ; if ( currentSlide ) { currentSlide . active = false ; } const nextSlide = this . _slides . get ( index ) ; if ( nextSlide ) { this . _currentActiveSlide = index ; nextSlide . active = true ; this . activeSlide = index ; } } /**
     * Starts loop of auto changing of slides
     */ private restartTimer ( ) { this . resetTimer ( ) ; const interval = + this . interval ; if ( ! isNaN ( interval ) && interval > 0 ) { this . currentInterval = setInterval ( ( ) => { const nInterval = + this . interval ; if ( this . isPlaying && ! isNaN ( this . interval ) && nInterval > 0 && this . slides . length ) { this . nextSlide ( ) ; } else { this . pause ( ) ; } } , interval ) ; } } /**
     * Stops loop of auto changing of slides
     */ private resetTimer ( ) { if ( this . currentInterval ) { clearInterval ( this . currentInterval ) ; this . currentInterval = void 0 ; } } protected hasClass ( el , className ) { if ( el . classList ) { return el . classList . contains ( className ) ; } else { return ! ! el . className . match ( new RegExp ( '(\\s|^)' + className + '(\\s|$)' ) ) ; } } protected classAdd ( el , className ) { if ( el . classList ) { el . classList . add ( className ) ; } else if ( ! this . hasClass ( el , className ) ) { el . className += ' ' + className ; } } protected removeClass ( el , className ) { if ( el . classList ) { el . classList . remove ( className ) ; } else if ( this . hasClass ( el , className ) ) { const reg = new RegExp ( '(\\s|^)' + className + '(\\s|$)' ) ; el . className = el . className . replace ( reg , ' ' ) ; } } @ HostListener ( 'keyup' , [ '$event' ] ) keyboardControl ( event ) { if ( this . keyboard ) { if ( event . keyCode === 39 ) { this . nextSlide ( ) ; } if ( event . keyCode === 37 ) { this . previousSlide ( ) ; } } } @ HostListener ( 'click' , [ '$event' ] ) focus ( ) { this . el . nativeElement . focus ( ) ; } }