import { DOCUMENT } from '@angular/common' ; import { Inject , Injectable } from '@angular/core' ; import { ActivatedRoute , Router } from '@angular/router' ; import { IDocumentationPage } from '../../interfaces/IDocumentationPage' ; import { ILink } from '../../interfaces/ILink' ; import { ISection } from '../../interfaces/ISection' ; import { AppConfiguration } from '../app-configuration/app-configuration.service' ; const NAVIGATION_TOP_OFFSET = 50 ; const NAVIGATION_ACTIVE_OFFSET = 51 ; @ Injectable ( { providedIn : 'root' } ) export class NavigationService { private activeFragment : string = null ; private renderingCount : number = 0 ; constructor ( @ Inject ( DOCUMENT ) private _document , private _activeRoute , private _router , private _appConfig ) { } getScrollTop ( ) { return window . pageYOffset || document . documentElement . scrollTop || document . body . scrollTop || 0 ; } getTopOffset ( ) { return NAVIGATION_TOP_OFFSET ; } isScrolledToBottom ( ) { return ( this . getScrollTop ( ) + window . innerHeight ) >= this . _document . body . offsetHeight ; } isFragmentActive ( id ) { const element = document . getElementById ( id ) ; if ( id === this . activeFragment ) { return true ; } if ( element ) { const bounds = element . getBoundingClientRect ( ) ; if ( bounds . top <= NAVIGATION_ACTIVE_OFFSET && bounds . bottom > NAVIGATION_ACTIVE_OFFSET ) { return true ; } } return false ; } setActiveFragment ( id , replaceOnly = false , updateUrl = true ) { if ( updateUrl ) { if ( ! replaceOnly || this . urlHasFragment ( ) ) { this . _router . navigate ( [ ] , { fragment : id , replaceUrl : true } ) ; } } else { this . activeFragment = id ; } } scrollToFragment ( id ) { const element = document . getElementById ( id ) ; if ( element ) { element . scrollIntoView ( true ) ; if ( ! this . isScrolledToBottom ( ) ) { window . scrollBy ( 0 , - this . getTopOffset ( ) ) ; } } } scrollOnNavigationChange ( url ) { const parsed = this . _router . parseUrl ( url ) ; if ( parsed . fragment ) { if ( ! this . isFragmentActive ( parsed . fragment ) || parsed . fragment !== this . _activeRoute . snapshot . fragment ) { setTimeout ( ( ) => { this . scrollToFragment ( parsed . fragment ) ; } ) ; } } else { document . body . scrollTop = document . documentElement . scrollTop = 0 ; } this . activeFragment = null ; } setSectionIds ( sections ) { for ( let section of sections ) { if ( ! section . id ) { section . id = section . component . replace ( /^(?:Components|Css|Charts)(.+)Component$/ , '$1' ) . replace ( /(.)([A-Z]+)/g , '$1-$2' ) . toLowerCase ( ) ; } } } getComponentLink ( component ) { for ( let pageName of this . _appConfig . documentationPages ) { const page = < IDocumentationPage > this . _appConfig . getConfigurationData ( pageName ) ; const pageLink = page . id || page . title . toLowerCase ( ) ; for ( let category of page . categories ) { const section = category . sections . find ( s => s . component === component ) ; if ( section ) { return { title : section . title , link : `/${ pageLink }/${ category . link }` , fragment : section . id } ; } } } } private urlHasFragment ( ) { return this . _activeRoute . snapshot . fragment && this . _activeRoute . snapshot . fragment . length ; } }