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 88 89 90 91 92 93 94 95 96 97 98 | 12x 12x 12x 12x 5x 5x 4x 3x 4x 4x 4x | import { DOCUMENT } from '@angular/common'; import { AfterContentInit, AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, Inject, Input, Renderer2, ViewChild, } from '@angular/core'; import { v4 as uuid } from 'uuid'; /** * @description * This component can be wrapped around listings to provide better accessibility support for * longer listings by adding a skip link. * * The skip link is only visible when it receives keyboard focus (similar to the "Skip to main content" link) * and skips to the element with the ID provided by the `skipToElementId` input parameter. * * If no `skipToElementId` is provided or the ID is invalid, the component generates a * target element after the listing where the focus is set on. * * If a valid `skipToElementId` is provided, the component does not have to be wrapped around a listing element, * since it does not have to generate a target element after the listing. * * IMPORTANT: If the target element is not natively focusable (like a button or link), * the element needs a `tabindex="-1"` to be programmatically focusable (like `breadcrumb.component.html`). * * The skip link is not visible on mobile and tablet. * * @example * <ish-skip-content-link> * <ul>...</ul> * </ish-skip-content-link> * * @example * <ish-skip-content-link skipToElementId="validElementId" /> * <ul>...</ul> */ @Component({ selector: 'ish-skip-content-link', templateUrl: './skip-content-link.component.html', changeDetection: ChangeDetectionStrategy.OnPush, }) export class SkipContentLinkComponent implements AfterContentInit, AfterViewInit { /** * Translation key for the skip link text. */ @Input() linkText = 'common.skip_content.link.text.default'; /** * A valid element-ID to skip to when the link is clicked. * If not natively focusable (like a button or link), add `tabindex="-1"` to the target element. */ @Input() skipToElementId: string; @ViewChild('skipContentLink') skipContentLinkElementRef: ElementRef; generatedElementAfterListingId: string; constructor(@Inject(DOCUMENT) private document: Document, private renderer: Renderer2) {} // cannot set the ID in `ngAfterViewInit()` because the ID in the HTML would be undefined ngAfterContentInit() { if (this.isTargetElementIdMissingOrInvalid()) { // setting this variable will generate an empty target element after the listing this.generatedElementAfterListingId = `element-after-listing-${uuid()}`; } } // click-listener has to be set here because the `skipContentLinkElementRef` is not yet available in `ngAfterContentInit()` ngAfterViewInit() { this.setCustomClickListenerForSkipLink(); } /** * Sets up a custom click listener for the skip link to handle focus and scrolling. */ private setCustomClickListenerForSkipLink() { this.renderer.listen(this.skipContentLinkElementRef.nativeElement, 'click', (event: Event) => { event.preventDefault(); const targetElement = this.document.getElementById(this.skipToElementId || this.generatedElementAfterListingId); Iif (targetElement) { targetElement.focus({ preventScroll: true }); targetElement.scrollIntoView({ behavior: 'smooth', block: 'center' }); } }); } private isTargetElementIdMissingOrInvalid(): boolean { return !this.skipToElementId || !this.document.getElementById(this.skipToElementId); } } |