MOBILE-4065 directive: Improve ariaButtonClick directive
parent
15cdc017e5
commit
7fac6895d9
|
@ -1,10 +1,14 @@
|
|||
<img *ngIf="avatarUrl" [src]="avatarUrl" [alt]="'core.pictureof' | translate:{$a: fullname}" core-external-content
|
||||
onError="this.src='assets/img/user-avatar.png'" (ariaButtonClick)="gotoProfile($event)" [attr.aria-hidden]="!linkProfile"
|
||||
[attr.role]="linkProfile ? 'button' : null" [attr.tabindex]="linkProfile ? 0 : null" [class.clickable]="linkProfile">
|
||||
<img *ngIf="avatarUrl && linkProfile" [src]="avatarUrl" [alt]="'core.pictureof' | translate:{$a: fullname}" core-external-content
|
||||
onError="this.src='assets/img/user-avatar.png'" (ariaButtonClick)="gotoProfile($event)">
|
||||
|
||||
<img *ngIf="!avatarUrl" src="assets/img/user-avatar.png" [alt]="'core.pictureof' | translate:{$a: fullname}"
|
||||
(ariaButtonClick)="gotoProfile($event)" [attr.aria-hidden]="!linkProfile" [attr.role]="linkProfile ? 'button' : null"
|
||||
[attr.tabindex]="linkProfile ? 0 : null">
|
||||
<img *ngIf="avatarUrl && !linkProfile" [src]="avatarUrl" [alt]="'core.pictureof' | translate:{$a: fullname}" core-external-content
|
||||
onError="this.src='assets/img/user-avatar.png'" aria-hidden="true">
|
||||
|
||||
<img *ngIf="!avatarUrl && linkProfile" src="assets/img/user-avatar.png" [alt]="'core.pictureof' | translate:{$a: fullname}"
|
||||
(ariaButtonClick)="gotoProfile($event)">
|
||||
|
||||
<img *ngIf="!avatarUrl && !linkProfile" src="assets/img/user-avatar.png" [alt]="'core.pictureof' | translate:{$a: fullname}"
|
||||
aria-hidden="true">
|
||||
|
||||
<span *ngIf="checkOnline && isOnline()" class="contact-status online" role="status" [attr.aria-label]="'core.online' | translate">
|
||||
</span>
|
||||
|
|
|
@ -5,9 +5,6 @@
|
|||
width: var(--core-avatar-size);
|
||||
height: var(--core-avatar-size);
|
||||
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
img {
|
||||
border-radius: 50%;
|
||||
width: var(--core-avatar-size);
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Directive, ElementRef, OnInit, Output, EventEmitter } from '@angular/core';
|
||||
import { Directive, ElementRef, OnInit, Output, EventEmitter, OnChanges, SimpleChanges, Input } from '@angular/core';
|
||||
import { CoreDom } from '@singletons/dom';
|
||||
|
||||
/**
|
||||
|
@ -21,10 +21,11 @@ import { CoreDom } from '@singletons/dom';
|
|||
@Directive({
|
||||
selector: '[ariaButtonClick]',
|
||||
})
|
||||
export class CoreAriaButtonClickDirective implements OnInit {
|
||||
export class CoreAriaButtonClickDirective implements OnInit, OnChanges {
|
||||
|
||||
protected element: HTMLElement;
|
||||
|
||||
@Input() disabled = false;
|
||||
@Output() ariaButtonClick = new EventEmitter();
|
||||
|
||||
constructor(
|
||||
|
@ -34,10 +35,27 @@ export class CoreAriaButtonClickDirective implements OnInit {
|
|||
}
|
||||
|
||||
/**
|
||||
* Initialize actions.
|
||||
* @inheritdoc
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
CoreDom.onActivate(this.element, (event) => this.ariaButtonClick.emit(event));
|
||||
CoreDom.initializeClickableElementA11y(this.element, (event) => this.ariaButtonClick.emit(event));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (!changes.disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.element.getAttribute('tabindex') === '0' && this.disabled) {
|
||||
this.element.setAttribute('tabindex', '-1');
|
||||
}
|
||||
|
||||
if (this.element.getAttribute('tabindex') === '-1' && !this.disabled) {
|
||||
this.element.setAttribute('tabindex', '0');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -610,12 +610,7 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncCompo
|
|||
return;
|
||||
}
|
||||
|
||||
if (element.tagName !== 'BUTTON' && element.tagName !== 'A') {
|
||||
element.setAttribute('tabindex', '0');
|
||||
element.setAttribute('role', 'button');
|
||||
}
|
||||
|
||||
CoreDom.onActivate(element, async (event) => {
|
||||
CoreDom.initializeClickableElementA11y(element, async (event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
|
|
|
@ -57,12 +57,7 @@ export class CoreLinkDirective implements OnInit {
|
|||
* Function executed when the component is initialized.
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
if (this.element.tagName != 'BUTTON' && this.element.tagName != 'A') {
|
||||
this.element.setAttribute('tabindex', '0');
|
||||
this.element.setAttribute('role', 'button');
|
||||
}
|
||||
|
||||
CoreDom.onActivate(this.element, (event) => this.performAction(event));
|
||||
CoreDom.initializeClickableElementA11y(this.element, (event) => this.performAction(event));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<core-user-avatar *ngIf="(alwaysShow || isMainScreen) && siteInfo" [user]="siteInfo" class="core-bar-button-image clickable"
|
||||
[linkProfile]="false" (ariaButtonClick)="openUserMenu($event)" [userTour]="userTour" role="button" tabindex="0"
|
||||
[linkProfile]="false" (ariaButtonClick)="openUserMenu($event)" [userTour]="userTour"
|
||||
[attr.aria-label]="'core.user.useraccount' | translate">
|
||||
</core-user-avatar>
|
||||
|
|
|
@ -514,8 +514,26 @@ export class CoreDom {
|
|||
*
|
||||
* @param element Element to listen to events.
|
||||
* @param callback Callback to call when clicked or the key is pressed.
|
||||
* @deprecated since 4.1.1: Use initializeClickableElementA11y instead.
|
||||
*/
|
||||
static onActivate(element: HTMLElement, callback: (event: MouseEvent | KeyboardEvent) => void): void {
|
||||
static onActivate(
|
||||
element: HTMLElement & {disabled?: boolean},
|
||||
callback: (event: MouseEvent | KeyboardEvent) => void,
|
||||
): void {
|
||||
this.initializeClickableElementA11y(element, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a clickable element a11y calling the click action when pressed enter or space
|
||||
* and adding tabindex and role if needed.
|
||||
*
|
||||
* @param element Element to listen to events.
|
||||
* @param callback Callback to call when clicked or the key is pressed.
|
||||
*/
|
||||
static initializeClickableElementA11y(
|
||||
element: HTMLElement & {disabled?: boolean},
|
||||
callback: (event: MouseEvent | KeyboardEvent) => void,
|
||||
): void {
|
||||
element.addEventListener('click', (event) => callback(event));
|
||||
|
||||
element.addEventListener('keydown', (event) => {
|
||||
|
@ -526,10 +544,27 @@ export class CoreDom {
|
|||
});
|
||||
|
||||
element.addEventListener('keyup', (event) => {
|
||||
if ((event.key == ' ' || event.key == 'Enter')) {
|
||||
if (event.key === ' ' || event.key === 'Enter') {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
callback(event);
|
||||
}
|
||||
});
|
||||
|
||||
if (element.tagName !== 'BUTTON' && element.tagName !== 'A') {
|
||||
// Set tabindex if not previously set.
|
||||
if (element.getAttribute('tabindex') === null) {
|
||||
element.setAttribute('tabindex', element.disabled ? '-1' : '0');
|
||||
}
|
||||
|
||||
// Set role if not previously set.
|
||||
if (!element.getAttribute('role')) {
|
||||
element.setAttribute('role', 'button');
|
||||
}
|
||||
|
||||
element.classList.add('clickable');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue