import { Inject , Injectable , OnDestroy } from '@angular/core' ; import { ActivatedRoute , NavigationEnd , Router } from '@angular/router' ; import { Title } from '@angular/platform-browser' ; import { DOCUMENT } from '@angular/common' ; import { TranslateService } from '@ngx-translate/core' ; import { filter , map , mergeMap , takeUntil } from 'rxjs/operators' ; import { Subject } from 'rxjs' ; /**
 * DocumentMetaService - Service for updating document metadata
 *
 * Inspired & adapted from: https://gist.github.com/LA1CH3/718588765d56a8932de52c64c3561dcf
 */ @ Injectable ( { providedIn : 'root' } ) export class ObDocumentMetaService implements OnDestroy { public titleSeparator = ' · ' ; public titleSuffix = '' ; public description = '' ; private readonly headElement : HTMLElement ; private readonly metaDescription : HTMLElement ; private readonly currentMetaInformation = { title : '' , description : '' } ; private readonly unsubscribe = new Subject ( ) ; constructor ( private readonly router , private readonly activatedRoute , private readonly titleService , private readonly translate , @ Inject ( DOCUMENT ) private readonly document ) { this . headElement = this . document . querySelector ( 'head' ) ; this . metaDescription = this . getOrCreateMetaElement ( 'description' ) ; this . translate . onLangChange . pipe ( takeUntil ( this . unsubscribe ) ) . subscribe ( this . updateMetaInformation . bind ( this ) ) ; router . events . pipe ( filter ( event => event instanceof NavigationEnd ) , map ( ( ) => this . activatedRoute ) , map ( route => { while ( route . firstChild ) { route = route . firstChild ; } return route ; } ) , filter ( route => route . outlet === 'primary' ) , mergeMap ( route => route . data ) , takeUntil ( this . unsubscribe ) ) . subscribe ( data => { this . currentMetaInformation . title = data . title ; this . currentMetaInformation . description = data . description || this . description ; this . updateMetaInformation ( ) ; } ) ; } ngOnDestroy ( ) { this . unsubscribe . next ( ) ; this . unsubscribe . complete ( ) ; } public setTitle ( title , separator = this . titleSeparator , suffix = this . titleSuffix ) { if ( title ) { this . translate . get ( [ title , suffix ] ) . pipe ( takeUntil ( this . unsubscribe ) , map ( translation => ( translation [ suffix ] ? `${ translation [ title ] }${ separator }${ translation [ suffix ] }` : translation [ title ] ) ) ) . subscribe ( text => this . titleService . setTitle ( text ) ) ; } else if ( suffix ) { this . titleService . setTitle ( this . translate . instant ( suffix ) ) ; } } public getMetaDescription ( ) { return this . metaDescription . getAttribute ( 'content' ) ; } public setDescription ( description ) { if ( description && description !== '' ) { this . translate . get ( description ) . pipe ( takeUntil ( this . unsubscribe ) ) . subscribe ( translation => { this . metaDescription . setAttribute ( 'content' , translation ) ; } ) ; } else { this . metaDescription . setAttribute ( 'content' , '' ) ; } } private getOrCreateMetaElement ( name ) { let meta = this . headElement . querySelector ( `meta[name=${ name }]` ) ; if ( meta === null ) { meta = this . document . createElement ( 'meta' ) ; meta . setAttribute ( 'name' , name ) ; this . headElement . appendChild ( meta ) ; } return meta ; } private updateMetaInformation ( ) { this . setTitle ( this . currentMetaInformation . title ) ; this . setDescription ( this . currentMetaInformation . description ) ; } }