Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 12x 12x 12x 12x 4x 8x 8x 8x 8x 2x 6x 6x 4x 4x 4x 4x 2x | import { ArticleContentComponent } from '../../../../components/article-content/article-content.component';
import { ArticleSidebarActionsComponent } from '../../../../components/article-sidebar-actions/article-sidebar-actions.component';
import { ArticlePageService } from '../../../../services/article-page.service';
import { DOCUMENT } from '@angular/common';
import { afterNextRender, ChangeDetectionStrategy, Component, DestroyRef, inject, Injector } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { ActivatedRoute } from '@angular/router';
import { LoggerService } from '@drevo-web/core';
import { ModerationResult } from '@drevo-web/shared';
import { distinctUntilChanged } from 'rxjs/operators';
@Component({
selector: 'app-article-content-tab',
imports: [ArticleContentComponent, ArticleSidebarActionsComponent],
templateUrl: './article-content-tab.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ArticleContentTabComponent {
private readonly pageService = inject(ArticlePageService);
readonly article = this.pageService.article;
readonly editUrl = this.pageService.editUrl;
private readonly document = inject(DOCUMENT);
private readonly route = inject(ActivatedRoute);
private readonly destroyRef = inject(DestroyRef);
private readonly injector = inject(Injector);
private readonly logger = inject(LoggerService).withContext('ArticleContentTab');
private currentFragment: string | undefined = undefined;
onModerated(result: ModerationResult): void {
this.pageService.updateApproval(result.approved, result.comment);
}
onTopicsChanged(topics: ReadonlyArray<number>): void {
this.pageService.updateTopics(topics);
}
constructor() {
this.route.fragment.pipe(distinctUntilChanged(), takeUntilDestroyed(this.destroyRef)).subscribe(fragment => {
this.currentFragment = fragment ?? undefined;
this.scrollToFragment();
});
}
private scrollToFragment(): void {
afterNextRender(
() => {
if (!this.currentFragment || !this.article()) {
return;
}
let targetElement: Element | undefined = undefined;
try {
targetElement =
this.document.getElementById(this.currentFragment) ||
this.document.querySelector(`a[name="${CSS.escape(this.currentFragment)}"]`) ||
undefined;
} catch (error) {
this.logger.error('scrollToFragment: querySelector failed', { error });
return;
}
if (!targetElement) {
return;
}
const mainContainer = this.document.getElementById('content');
if (mainContainer) {
const targetRect = targetElement.getBoundingClientRect();
const containerRect = mainContainer.getBoundingClientRect();
const scrollTop = targetRect.top - containerRect.top + mainContainer.scrollTop;
mainContainer.scrollTo({
top: scrollTop,
behavior: 'smooth',
});
} else {
targetElement.scrollIntoView({
behavior: 'smooth',
block: 'start',
});
}
},
{ injector: this.injector },
);
}
}
|