import { DOCUMENT } from '@angular/common'; import { Component, EventEmitter, Inject, OnInit, Output, Input } from '@angular/core'; import { BaseComponent } from '@common/base/base.component'; import { interval, Subject, Subscription } from 'rxjs'; import { distinctUntilChanged } from 'rxjs/operators'; import { type } from 'os'; interface Link { /* id of the section*/ id: string; /* header type h3/h4 */ type: string; /* If the anchor is in view of the page */ active: boolean; /* name of the anchor */ name: string; /* top offset px of the anchor */ top: number; page: number; section: number; show: boolean; selected: boolean; } @Component({ selector: 'table-of-contents', styleUrls: ['./table-of-contents.scss'], templateUrl: './table-of-contents.html' }) export class TableOfContents extends BaseComponent implements OnInit { links: Link[] = []; container: string; headerSelectors = '.toc-page-header, .toc-section-header, .toc-copositeField-header'; @Output() stepFound = new EventEmitter(); subscription: Subscription; linksSubject: Subject = new Subject(); @Input() isActive: boolean; show: boolean = false; constructor( @Inject(DOCUMENT) private _document: Document) { super(); } ngOnInit(): void { //emit value every 500ms const source = interval(500); this.subscription = source.subscribe(val => { const headers = Array.from(this._document.querySelectorAll(this.headerSelectors)) as HTMLElement[]; this.linksSubject.next(headers); }); this.linksSubject.asObservable() .pipe(distinctUntilChanged((p: HTMLElement[], q: HTMLElement[]) => JSON.stringify(p) == JSON.stringify(q))) .subscribe(headers => { const links: Array = []; if (headers.length) { let page; let section; let show for (const header of headers) { let name; let id; if (header.classList.contains('toc-page-header')) { name = header.innerText.trim().replace(/^link/, ''); id = header.id; page = header.id.split('_')[1]; section = undefined; show = true; } else if (header.classList.contains('toc-section-header')) { name = header.childNodes[0].childNodes[0].childNodes[0].childNodes[0].childNodes[0].nodeValue.trim().replace(/^link/, ''); id = header.id; page = header.id.split('.')[1]; section = header.id; show = false; } else if (header.classList.contains('toc-copositeField-header')) { name = (header.childNodes[0]).nodeValue.trim().replace(/^link/, ''); id = header.id; // id = header.parentElement.parentElement.parentElement.id; show = false; } const { top } = header.getBoundingClientRect(); links.push({ name, id, type: header.tagName.toLowerCase(), top: top, active: false, page: page, section: section, show: show, selected: false }); } } this.links = links; // Initialize selected for button next on dataset wizard component editor this.links[0].selected = true; }) } goToStep(link: Link) { // this.selectedLinkId = link.id; this.stepFound.emit({ page: link.page, section: link.section }); setTimeout(() => { const target = document.getElementById(link.id); target.scrollIntoView(true); var scrolledY = window.scrollY; if (scrolledY) { window.scroll(0, scrolledY - 70); } }, 500); } toggle(headerLink: Link) { const page = +headerLink.id.split("_", 2)[1]; let innerPage; for (const link of this.links) { link.selected = false; if (link.type === 'mat-expansion-panel') { innerPage = +link.name.split(" ",1)[0]; } else if (link.type === 'h5') { innerPage = +link.name.split(".",1)[0]; } if (page + 1 === innerPage && link.type !== 'span') { link.show = !link.show; } } headerLink.selected = true; } getIndex(link: Link): number { return +link.id.split("_", 2)[1]; } } export interface LinkToScroll { page: number; section: number; }