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);
}
}
|