| 43 | }, |
| 44 | }) |
| 45 | export class AppComponent { |
| 46 | private readonly document = inject(DOCUMENT); |
| 47 | private readonly router = inject(Router); |
| 48 | private readonly headerService = inject(HeaderService); |
| 49 | |
| 50 | protected isBrowser = isPlatformBrowser(inject(PLATFORM_ID)); |
| 51 | |
| 52 | protected readonly displaySecondaryNav = signal(false); |
| 53 | protected readonly displayFooter = signal(false); |
| 54 | protected readonly displaySearchDialog = inject(IS_SEARCH_DIALOG_OPEN); |
| 55 | |
| 56 | constructor() { |
| 57 | this.closeSearchDialogOnNavigationSkipped(); |
| 58 | this.router.events |
| 59 | .pipe( |
| 60 | filter((e): e is NavigationEnd => e instanceof NavigationEnd), |
| 61 | map((event) => event.urlAfterRedirects), |
| 62 | ) |
| 63 | .subscribe((url) => { |
| 64 | // We can't use an input binded to the route here |
| 65 | // because AppComponent itself is not a routed component |
| 66 | // so we access it via the snapshot |
| 67 | const activatedRoute = getActivatedRouteSnapshotFromRouter(this.router); |
| 68 | this.displayFooter.set(!activatedRoute.data['hideFooter']); |
| 69 | this.displaySecondaryNav.set(activatedRoute.data['displaySecondaryNav']); |
| 70 | |
| 71 | this.displaySearchDialog.set(false); |
| 72 | this.updateCanonicalLink(url); |
| 73 | }); |
| 74 | } |
| 75 | |
| 76 | protected focusFirstHeading(): void { |
| 77 | const main = this.document.querySelector<HTMLElement>('main'); |
| 78 | if (main) { |
| 79 | main.setAttribute('tabindex', '-1'); |
| 80 | main.focus(); |
| 81 | return; |
| 82 | } |
| 83 | |
| 84 | // Fallback: focus the first h1 (legacy support for pages without main) |
| 85 | const h1 = this.document.querySelector<HTMLHeadingElement>('h1:not(docs-top-level-banner h1)'); |
| 86 | h1?.focus(); |
| 87 | } |
| 88 | |
| 89 | protected setSearchDialogVisibilityOnKeyPress(event: KeyboardEvent): void { |
| 90 | if (event.key === SEARCH_TRIGGER_KEY && (event.metaKey || event.ctrlKey)) { |
| 91 | event.preventDefault(); |
| 92 | this.displaySearchDialog.update((display) => !display); |
| 93 | } |
| 94 | |
| 95 | if (event.key === ESCAPE && this.displaySearchDialog()) { |
| 96 | event.preventDefault(); |
| 97 | this.displaySearchDialog.set(false); |
| 98 | } |
| 99 | |
| 100 | if (isDevMode() && event.key === 'o' && (event.metaKey || event.ctrlKey)) { |
| 101 | // In debug this shortcut allows us to open the same page on adev |
| 102 | // Helpful to compare differences |
nothing calls this directly
no test coverage detected
searching dependent graphs…