import { Component, OnInit, AfterViewChecked, ViewEncapsulation, ViewChild, AfterContentInit, AfterViewInit } from '@angular/core'; import { UserGuideService } from '@app/core/services/user-guide/user-guide.service'; import { BaseComponent } from '@common/base/base.component'; import { takeUntil } from 'rxjs/internal/operators/takeUntil'; import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser'; import { LanguageService } from '@app/core/services/language/language.service'; import { HttpClient } from '@angular/common/http'; import { MatomoService } from '@app/core/services/matomo/matomo-service'; import { ElementRef } from '@angular/core'; import { interval, Subject } from 'rxjs'; import { ConfigurationService } from '@app/core/services/configuration/configuration.service'; @Component({ selector: 'app-user-guide-content', templateUrl: './user-guide-content.component.html', styleUrls: ['./user-guide-content.component.scss'] }) export class UserGuideContentComponent extends BaseComponent implements OnInit { readonly useInnerHTML: boolean = false; //GK: Change for TESTING PURPOSES ONLY guideHTML: any; guideHTMLUrl: SafeResourceUrl; sanitizedGuideUrl: any; private scrollEvent: EventListener; private tocScrollEvent: EventListener; private _transformed: Subject = new Subject(); private _parsed: Subject = new Subject(); @ViewChild('guide', {static: false}) guide: ElementRef; constructor( private userGuideService: UserGuideService, private sanitizer: DomSanitizer, private languageService: LanguageService, private httpClient: HttpClient, private matomoService: MatomoService, private configurationService: ConfigurationService ) { super(); } ngOnInit() { this.matomoService.trackPageView('User Guide Content'); this.scrollEvent = ((ev) => this.scroll(ev)); this.tocScrollEvent = ((ev) => { this.activeToc(ev); this.scroll(ev); }); this.userGuideService.getUserGuide(this.languageService.getCurrentLanguage()) .pipe(takeUntil(this._destroyed)) .subscribe(response => { const blob = new Blob([response.body], { type: 'text/html' }); if (this.useInnerHTML) { this.readBlob(blob); } else { this.guideHTMLUrl = this.sanitizer.bypassSecurityTrustResourceUrl((window.URL ? URL : webkitURL).createObjectURL(blob)); //GK: In case the app is in localhost (dev/debug build) apply the following transformation //in order to show the user guide's images if (this.guideHTMLUrl && this.configurationService.app.includes('localhost')) { interval(1000).pipe(takeUntil(this._transformed)).subscribe(() => this.transform()); } } // this.guideHTML = this.sanitizer.sanitize(SecurityContext.HTML, blob); // this.sanitizedGuideUrl = this.sanitizer.sanitize(SecurityContext.URL, this.guideHTMLUrl); // console.log(this.guideHTMLUrl); }); } readBlob(blob: Blob) { const fr = new FileReader(); fr.onload = ev => { const HTMLstring = fr.result as string; this.guideHTML = this.sanitizer.bypassSecurityTrustHtml(HTMLstring); this.addScripts(HTMLstring); if (this.guideHTML) { interval(1000).pipe(takeUntil(this._transformed)).subscribe(() => this.transform()); interval(1000).pipe(takeUntil(this._parsed)).subscribe(() => this.parse()); } }; fr.readAsText(blob); } activeToc(ev: Event) { const current = document.getElementsByClassName('active'); if (current.length > 0) { current[0].classList.remove('active'); } (ev.currentTarget as Element).classList.add('active'); } scroll(ev: Event) { document.getElementById((ev.currentTarget as Element).getAttribute('path')).scrollIntoView({ behavior: 'smooth', block: 'start' }); } private parse() { const specialElements: HTMLCollection = document.getElementsByTagName('a'); for (let i = 0; i < specialElements.length; i++) { const element = specialElements.item(i) as HTMLAnchorElement; if(element.href.includes('#')) { this.hrefToPath(element); element.removeEventListener('click', this.scrollEvent); element.addEventListener('click', this.scrollEvent); } if (!this._parsed.isStopped) { this._parsed.next(true); this._parsed.complete(); } } } private addScripts(HTMLString: string) { const fragment = document.createRange().createContextualFragment(HTMLString); this.guide.nativeElement.appendChild(fragment); } transform() { if (this.useInnerHTML) { const tocElements = document.getElementsByClassName('nav-link'); for (let i = 0; i < tocElements.length; i++) { const href = (tocElements[i] as HTMLAnchorElement).href; if (href.includes('#')) { this.hrefToPath(tocElements[i] as HTMLAnchorElement); tocElements[i].addEventListener('click', this.tocScrollEvent); tocElements[i].classList.add('tocElement'); if (!this._transformed.isStopped) { this._transformed.next(true); this._transformed.complete(); } } } } else { const userguide = document.getElementById('userguide') as HTMLIFrameElement; const images = userguide.contentWindow.document.getElementsByTagName('img'); for (let i = 0; i < images.length; i++) { const image = images[i]; image.src = `${this.configurationService.app}${image.src}`; if (!this._transformed.isStopped) { this._transformed.next(true); this._transformed.complete(); } } } } private hrefToPath(element: HTMLAnchorElement) { const href = element.href; const hashtagIndex = href.lastIndexOf('#'); element.removeAttribute('href'); element.setAttribute('path', href.slice(hashtagIndex + 1)); } }