ngx-admin/docs/app/@theme/components/fragment-target/fragment-target.directive.ts
2021-10-08 13:51:04 +03:00

72 lines
2 KiB
TypeScript

import { Directive, ElementRef, Inject, Input, OnDestroy, OnInit, Renderer2 } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { NB_WINDOW } from '@nebular/theme';
import { delay, takeWhile, publish, refCount } from 'rxjs/operators';
import { NgxTocElement, NgxTocStateService } from '../../services/toc-state.service';
@Directive({
// tslint:disable-next-line
selector: '[ngxFragment]',
})
export class NgxFragmentTargetDirective implements OnInit, OnDestroy, NgxTocElement {
@Input() ngxFragment: string;
@Input() ngxFragmentClass: string;
@Input() ngxFragmentSync: boolean = true;
private inView = false;
private alive = true;
private readonly marginFromTop = 120;
get fragment(): string {
return this.ngxFragment;
}
get element(): any {
return this.el.nativeElement;
}
get y(): number {
return this.element.getBoundingClientRect().y;
}
constructor(
private activatedRoute: ActivatedRoute,
@Inject(NB_WINDOW) private window,
private tocState: NgxTocStateService,
private el: ElementRef,
private renderer: Renderer2,
) {}
ngOnInit() {
this.ngxFragmentSync && this.tocState.add(this);
this.activatedRoute.fragment
.pipe(publish(null), refCount(), takeWhile(() => this.alive), delay(10))
.subscribe((fragment: string) => {
if (fragment && this.fragment === fragment && !this.inView) {
this.selectFragment();
} else {
this.deselectFragment();
}
});
}
selectFragment() {
this.ngxFragmentClass && this.renderer.addClass(this.el.nativeElement, this.ngxFragmentClass);
this.setInView(true);
this.window.scrollTo(0, this.el.nativeElement.offsetTop - this.marginFromTop);
}
deselectFragment() {
this.renderer.removeClass(this.el.nativeElement, this.ngxFragmentClass);
}
setInView(val: boolean) {
this.inView = val;
}
ngOnDestroy() {
this.alive = false;
this.ngxFragmentSync && this.tocState.remove(this);
}
}