2017-05-08 14:33:56 +03:00
|
|
|
import { AfterViewInit, Component, ElementRef, OnDestroy, OnInit, QueryList, ViewChildren } from '@angular/core';
|
|
|
|
import { Observable } from 'rxjs/Observable';
|
2017-05-02 10:13:10 -07:00
|
|
|
import { Subject } from 'rxjs/Subject';
|
2017-05-08 14:33:56 +03:00
|
|
|
import 'rxjs/add/observable/combineLatest';
|
2017-05-02 10:13:10 -07:00
|
|
|
import 'rxjs/add/operator/takeUntil';
|
2017-04-27 15:32:46 -07:00
|
|
|
|
2017-05-08 16:42:38 -07:00
|
|
|
import { ScrollService } from 'app/shared/scroll.service';
|
2017-04-27 15:32:46 -07:00
|
|
|
import { TocItem, TocService } from 'app/shared/toc.service';
|
|
|
|
|
|
|
|
@Component({
|
|
|
|
selector: 'aio-toc',
|
|
|
|
templateUrl: 'toc.component.html',
|
|
|
|
styles: []
|
|
|
|
})
|
2017-05-08 14:33:56 +03:00
|
|
|
export class TocComponent implements OnInit, AfterViewInit, OnDestroy {
|
2017-04-27 15:32:46 -07:00
|
|
|
|
2017-05-08 14:33:56 +03:00
|
|
|
activeIndex: number | null = null;
|
2017-04-27 15:32:46 -07:00
|
|
|
hasSecondary = false;
|
2017-05-06 09:30:18 +01:00
|
|
|
hasToc = false;
|
2017-05-06 22:16:54 -07:00
|
|
|
hostElement: HTMLElement;
|
2017-05-16 16:10:06 -07:00
|
|
|
isCollapsed = true;
|
2017-04-27 15:32:46 -07:00
|
|
|
isEmbedded = false;
|
2017-05-08 14:33:56 +03:00
|
|
|
@ViewChildren('tocItem') private items: QueryList<ElementRef>;
|
2017-05-02 10:13:10 -07:00
|
|
|
private onDestroy = new Subject();
|
2017-05-06 22:16:54 -07:00
|
|
|
private primaryMax = 4;
|
2017-04-27 15:32:46 -07:00
|
|
|
tocList: TocItem[];
|
|
|
|
|
|
|
|
constructor(
|
2017-05-08 16:42:38 -07:00
|
|
|
private scrollService: ScrollService,
|
2017-04-27 15:33:50 -07:00
|
|
|
elementRef: ElementRef,
|
2017-04-27 15:32:46 -07:00
|
|
|
private tocService: TocService) {
|
2017-05-06 22:16:54 -07:00
|
|
|
this.hostElement = elementRef.nativeElement;
|
|
|
|
this.isEmbedded = this.hostElement.className.indexOf('embedded') !== -1;
|
2017-04-27 15:32:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
ngOnInit() {
|
2017-05-02 10:13:10 -07:00
|
|
|
this.tocService.tocList
|
|
|
|
.takeUntil(this.onDestroy)
|
2017-05-08 14:33:56 +03:00
|
|
|
.subscribe(tocList => {
|
2017-05-02 10:13:10 -07:00
|
|
|
const count = tocList.length;
|
|
|
|
|
|
|
|
this.hasToc = count > 0;
|
|
|
|
this.hasSecondary = this.isEmbedded && this.hasToc && (count > this.primaryMax);
|
|
|
|
this.tocList = tocList;
|
|
|
|
|
|
|
|
if (this.hasSecondary) {
|
|
|
|
for (let i = this.primaryMax; i < count; i++) {
|
|
|
|
tocList[i].isSecondary = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-05-08 14:33:56 +03:00
|
|
|
ngAfterViewInit() {
|
|
|
|
if (!this.isEmbedded) {
|
|
|
|
this.tocService.activeItemIndex
|
|
|
|
.takeUntil(this.onDestroy)
|
|
|
|
.subscribe(index => this.activeIndex = index);
|
|
|
|
|
|
|
|
Observable.combineLatest(this.tocService.activeItemIndex, this.items.changes.startWith(this.items))
|
|
|
|
.takeUntil(this.onDestroy)
|
|
|
|
.subscribe(([index, items]) => {
|
|
|
|
if (index === null || index >= items.length) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const e = items.toArray()[index].nativeElement;
|
|
|
|
const p = e.offsetParent;
|
|
|
|
|
|
|
|
const eRect = e.getBoundingClientRect();
|
|
|
|
const pRect = p.getBoundingClientRect();
|
|
|
|
|
|
|
|
const isInViewport = (eRect.top >= pRect.top) && (eRect.bottom <= pRect.bottom);
|
|
|
|
|
|
|
|
if (!isInViewport) {
|
|
|
|
p.scrollTop += (eRect.top - pRect.top) - (p.clientHeight / 2);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-02 10:13:10 -07:00
|
|
|
ngOnDestroy() {
|
|
|
|
this.onDestroy.next();
|
2017-04-27 15:32:46 -07:00
|
|
|
}
|
|
|
|
|
2017-05-09 15:36:24 -07:00
|
|
|
toggle(canScroll = true) {
|
2017-05-16 16:10:06 -07:00
|
|
|
this.isCollapsed = !this.isCollapsed;
|
|
|
|
if (canScroll && this.isCollapsed) { this.toTop(); }
|
|
|
|
}
|
|
|
|
|
|
|
|
toTop() {
|
|
|
|
this.scrollService.scrollToTop();
|
2017-04-27 15:32:46 -07:00
|
|
|
}
|
|
|
|
}
|