import { Directive , AfterViewInit , ElementRef , Renderer , Input } from '@angular/core' ; import { Tabs , Tab } from 'ionic-angular' ; @ Directive ( { selector : '[scrollable-tabs]' , host : { '(window:resize)' : 'onResize($event)' } } ) export class ScrollableTabs implements AfterViewInit { @ Input ( 'scrollable-tabs' ) ionTabs : Tabs ; @ Input ( 'opts' ) opts : any = { } ; currentTabIndex : number ; tabs : Tab [ ] = [ ] ; nativeTabbar : HTMLElement ; constructor ( public elemRef , public renderer ) { } ngOnChanges ( changes ) { if ( changes . hasOwnProperty ( 'opts' ) ) { if ( changes [ 'opts' ] . currentValue . refresh ) { setTimeout ( ( ) => { this . setAnchorStyles ( ) ; this . scrollToselectedTab ( ) ; } , 300 ) ; } } } ngAfterViewInit ( ) { this . nativeTabbar = this . ionTabs . _tabbar . nativeElement ; this . tabs = this . ionTabs . _tabs ; this . currentTabIndex = typeof ( this . ionTabs . selectedIndex ) == "undefined" ? 0 : this . ionTabs . selectedIndex ; this . ionTabs . ionChange . subscribe ( ( ) => { this . scrollToselectedTab ( ) ; } ) ; for ( let i = 0 ; i < this . tabs . length ; i ++ ) { this . tabs [ i ] . ionSelect . subscribe ( ( ) => { this . currentTabIndex = i ; } ) ; } this . renderer . setElementStyle ( this . nativeTabbar , "overflow-x" , "scroll" ) ; this . renderer . setElementStyle ( this . nativeTabbar , "overflow-y" , "hidden" ) ; this . setAnchorStyles ( ) ; this . scrollToselectedTab ( ) ; } onResize ( event ) { this . setAnchorStyles ( ) ; setTimeout ( ( ) => { this . scrollToselectedTab ( ) ; } , 300 ) ; } setAnchorStyles ( ) { if ( typeof ( this . nativeTabbar ) != "undefined" ) { let tabBar_width = this . nativeTabbar . clientWidth ; let numOfTabs = this . tabs . length ; let numOfVisibleAnchors = 0 ; let sumOfVisibleAnchorWidth = 0 ; for ( let i = 0 ; i < numOfTabs ; i ++ ) { let element = this . nativeTabbar . children [ i ] ; if ( this . tabs [ i ] . _isShown ) { numOfVisibleAnchors ++ ; this . renderer . setElementStyle ( element , 'display' , 'inline-table' ) ; this . renderer . setElementStyle ( element , 'width' , '6rem' ) ; if ( element . classList . contains ( "has-title-only" ) ) { this . renderer . setElementStyle ( element , 'padding-top' , '1.5rem' ) ; } sumOfVisibleAnchorWidth += element . clientWidth ; } else { this . renderer . setElementStyle ( element , 'display' , 'none' ) ; } } if ( sumOfVisibleAnchorWidth < tabBar_width ) { let anchorWidth = tabBar_width / numOfVisibleAnchors ; for ( let i = 0 ; i < numOfTabs ; i ++ ) { let element = this . nativeTabbar . children [ i ] ; if ( ! element . classList . contains ( "tab-hidden" ) ) { this . renderer . setElementStyle ( element , 'width' , anchorWidth + 'px' ) ; } } } } } scrollToselectedTab ( ) { if ( typeof this . nativeTabbar != 'undefined' ) { let tabBar_width = this . nativeTabbar . clientWidth ; let selectedTab = this . nativeTabbar . children [ this . currentTabIndex ] ; let selectedTab_Width = selectedTab . clientWidth ; let selectedTab_LeftOffset = document . getElementById ( selectedTab . id ) . offsetLeft ; let selectedTab_mid = selectedTab_LeftOffset + ( selectedTab_Width / 2 ) ; let newScrollLeft = selectedTab_mid - ( tabBar_width / 2 ) ; this . scrollXTo ( newScrollLeft , 300 ) . then ( ( ) => { } ) ; } } scrollXTo ( x , duration = 300 ) { let tabbar = this . nativeTabbar ; if ( ! tabbar ) { return Promise . resolve ( ) ; } x = x || 0 ; let originalRaf = ( window [ window [ 'Zone' ] [ '__symbol__' ] ( 'requestAnimationFrame' ) ] || window [ window [ 'Zone' ] [ '__symbol__' ] ( 'webkitRequestAnimationFrame' ) ] ) ; let nativeRaf = originalRaf !== undefined ? originalRaf [ 'bind' ] ( window ) : window . requestAnimationFrame . bind ( window ) ; let fromX = tabbar . scrollLeft ; let maxAttempts = ( duration / 16 ) + 100 ; return new Promise ( resolve => { let startTime ; let attempts = 0 ; let isPlaying ; function step ( ) { attempts ++ ; if ( ! tabbar || ! isPlaying || attempts > maxAttempts ) { isPlaying = false ; resolve ( ) ; return ; } let time = Math . min ( 1 , ( ( Date . now ( ) - startTime ) / duration ) ) ; let easedT = ( -- time ) * time * time + 1 ; if ( fromX !== x ) { tabbar . scrollLeft = Math . floor ( ( easedT * ( x - fromX ) ) + fromX ) ; } if ( easedT < 1 ) { nativeRaf ( step ) ; } else { resolve ( ) ; } } isPlaying = true ; nativeRaf ( ( ) => { startTime = Date . now ( ) ; nativeRaf ( step ) ; } ) ; } ) ; } }