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