diff --git a/src/addons/calendar/components/calendar/addon-calendar-calendar.html b/src/addons/calendar/components/calendar/addon-calendar-calendar.html
index 7fe5c0da7..ccae4c3f1 100644
--- a/src/addons/calendar/components/calendar/addon-calendar-calendar.html
+++ b/src/addons/calendar/components/calendar/addon-calendar-calendar.html
@@ -58,9 +58,7 @@
[class.addon-calendar-event-past-day]="isPastMonth || day.ispast"
role="button cell"
tabindex="0"
- (click)="dayClicked(day.mday)"
- (keyup)="dayAction.keyUp($event, day.mday)"
- (keydown)="dayAction.keyDown($event)"
+ (ariaButtonClick)="dayClicked(day.mday)"
>
{{ day.mday }}
@@ -80,9 +78,7 @@
[class.addon-calendar-event-past]="event.ispast"
role="button"
tabindex="0"
- (click)="eventClicked(event, $event)"
- (keyup)="eventAction.keyUp($event, event)"
- (keydown)="eventAction.keyDown($event)"
+ (ariaButtonClick)="eventClicked(event, $event)"
>
{
-
- /**
- * @inheritdoc
- */
- click(event: Event, day: number): void {
- this.componentInstance.dayClicked(day);
- }
-
-}
-
-/**
- * Helper class to manage event button.
- */
-class AddonCalendarEventButton extends CoreAriaRoleButton {
-
- /**
- * @inheritdoc
- */
- click(event: Event, calendarEvent: AddonCalendarEventToDisplay): void {
- this.componentInstance.eventClicked(calendarEvent, event);
- }
-
-}
diff --git a/src/core/classes/aria-role-button.ts b/src/core/classes/aria-role-button.ts
deleted file mode 100644
index 28a019a14..000000000
--- a/src/core/classes/aria-role-button.ts
+++ /dev/null
@@ -1,70 +0,0 @@
-// (C) Copyright 2015 Moodle Pty Ltd.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-export abstract class CoreAriaRoleButton {
-
- componentInstance: T;
-
- constructor(componentInstance: T) {
- this.componentInstance = componentInstance;
- }
-
- /**
- * A11y key functionality that prevents keyDown events.
- *
- * @param event Event.
- */
- keyDown(event: KeyboardEvent): void {
- if ((event.key == ' ' || event.key == 'Enter') && this.isAllowed()) {
- event.preventDefault();
- event.stopPropagation();
- }
- }
-
- /**
- * A11y key functionality that translates space and enter keys to click action.
- *
- * @param event Event.
- * @param args Additional args.
- */
- keyUp(event: KeyboardEvent, ...args: unknown[]): void {
- if ((event.key == ' ' || event.key == 'Enter') && this.isAllowed()) {
- event.preventDefault();
- event.stopPropagation();
-
- this.click(event, ...args);
- }
- }
-
- /**
- * A11y click functionality.
- *
- * @param event Event.
- * @param args Additional args.
- */
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- click(event?: Event, ...args: unknown[]): void {
- // Nothing defined here.
- }
-
- /**
- * Checks if action is allowed in class.
- *
- * @returns If allowed.
- */
- isAllowed(): boolean {
- return true;
- }
-
-}
diff --git a/src/core/components/user-avatar/core-user-avatar.html b/src/core/components/user-avatar/core-user-avatar.html
index 4b8d7819d..474334be0 100644
--- a/src/core/components/user-avatar/core-user-avatar.html
+++ b/src/core/components/user-avatar/core-user-avatar.html
@@ -4,18 +4,15 @@
[alt]="'core.pictureof' | translate:{$a: fullname}"
core-external-content
onError="this.src='assets/img/user-avatar.png'"
- (click)="gotoProfile($event)"
+ (ariaButtonClick)="gotoProfile($event)"
[attr.aria-hidden]="!linkProfile"
[attr.role]="linkProfile ? 'button' : null"
- (keydown)="buttonAction.keyDown($event)"
- (keyup)="buttonAction.keyUp($event)"
[attr.tabindex]="linkProfile ? 0 : null"
[class.clickable]="linkProfile"
>
diff --git a/src/core/components/user-avatar/user-avatar.ts b/src/core/components/user-avatar/user-avatar.ts
index 6097a0371..28815d4b4 100644
--- a/src/core/components/user-avatar/user-avatar.ts
+++ b/src/core/components/user-avatar/user-avatar.ts
@@ -20,7 +20,6 @@ import { CoreUtils } from '@services/utils/utils';
import { CoreEventObserver, CoreEvents } from '@singletons/events';
import { CoreUserProvider, CoreUserBasicData } from '@features/user/services/user';
import { CoreNavigator } from '@services/navigator';
-import { CoreAriaRoleButton } from '@classes/aria-role-button';
/**
* Component to display a "user avatar".
@@ -39,15 +38,13 @@ export class CoreUserAvatarComponent implements OnInit, OnChanges, OnDestroy {
@Input() profileUrl?: string;
@Input() linkProfile = true; // Avoid linking to the profile if wanted.
@Input() fullname?: string;
- @Input() userId?: number; // If provided or found it will be used to link the image to the profile.
- @Input() courseId?: number;
+ @Input() protected userId?: number; // If provided or found it will be used to link the image to the profile.
+ @Input() protected courseId?: number;
@Input() checkOnline = false; // If want to check and show online status.
@Input() extraIcon?: string; // Extra icon to show near the avatar.
avatarUrl?: string;
- buttonAction: CoreUserAvatarButton;
-
// Variable to check if we consider this user online or not.
// @TODO: Use setting when available (see MDL-63972) so we can use site setting.
protected timetoshowusers = 300000; // Miliseconds default.
@@ -55,7 +52,6 @@ export class CoreUserAvatarComponent implements OnInit, OnChanges, OnDestroy {
protected pictureObserver: CoreEventObserver;
constructor() {
-
this.currentUserId = CoreSites.getCurrentSiteUserId();
this.pictureObserver = CoreEvents.on(
@@ -67,15 +63,12 @@ export class CoreUserAvatarComponent implements OnInit, OnChanges, OnDestroy {
},
CoreSites.getCurrentSiteId(),
);
-
- this.buttonAction = new CoreUserAvatarButton(this);
}
/**
* Component being initialized.
*/
ngOnInit(): void {
-
this.setFields();
}
@@ -137,14 +130,19 @@ export class CoreUserAvatarComponent implements OnInit, OnChanges, OnDestroy {
* @param event Click event.
*/
gotoProfile(event: Event): void {
- if (!this.buttonAction.isAllowed()) {
+ if (!this.linkProfile || !this.userId) {
return;
}
event.preventDefault();
event.stopPropagation();
- this.buttonAction.click();
+ CoreNavigator.navigateToSitePath('user', {
+ params: {
+ userId: this.userId,
+ courseId: this.courseId,
+ },
+ });
}
/**
@@ -156,32 +154,6 @@ export class CoreUserAvatarComponent implements OnInit, OnChanges, OnDestroy {
}
-/**
- * Helper class to manage rol button.
- */
-class CoreUserAvatarButton extends CoreAriaRoleButton {
-
- /**
- * @inheritdoc
- */
- click(): void {
- CoreNavigator.navigateToSitePath('user', {
- params: {
- userId: this.componentInstance.userId,
- courseId: this.componentInstance.courseId,
- },
- });
- }
-
- /**
- * @inheritdoc
- */
- isAllowed(): boolean {
- return this.componentInstance.linkProfile && !!this.componentInstance.userId;
- }
-
-}
-
/**
* Type with all possible formats of user.
*/
diff --git a/src/core/directives/aria-button.ts b/src/core/directives/aria-button.ts
new file mode 100644
index 000000000..092c53737
--- /dev/null
+++ b/src/core/directives/aria-button.ts
@@ -0,0 +1,57 @@
+// (C) Copyright 2015 Moodle Pty Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import { Directive, ElementRef, OnInit, Output, EventEmitter } from '@angular/core';
+
+/**
+ * Directive to emulate click and key actions following aria role button.
+ */
+@Directive({
+ selector: '[ariaButtonClick]',
+})
+export class CoreAriaButtonClickDirective implements OnInit {
+
+ protected element: HTMLElement;
+
+ @Output() ariaButtonClick = new EventEmitter();
+
+ constructor(
+ element: ElementRef,
+ ) {
+ this.element = element.nativeElement;
+ }
+
+ /**
+ * Initialize actions.
+ */
+ ngOnInit(): void {
+ this.element.addEventListener('click', async (event) => {
+ this.ariaButtonClick.emit(event);
+ });
+
+ this.element.addEventListener('keydown', async (event) => {
+ if ((event.key == ' ' || event.key == 'Enter')) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ });
+
+ this.element.addEventListener('keyup', async (event) => {
+ if ((event.key == ' ' || event.key == 'Enter')) {
+ this.ariaButtonClick.emit(event);
+ }
+ });
+ }
+
+}
diff --git a/src/core/directives/directives.module.ts b/src/core/directives/directives.module.ts
index 3cf6d3303..b83ee4534 100644
--- a/src/core/directives/directives.module.ts
+++ b/src/core/directives/directives.module.ts
@@ -24,6 +24,7 @@ import { CoreLinkDirective } from './link';
import { CoreLongPressDirective } from './long-press';
import { CoreSupressEventsDirective } from './supress-events';
import { CoreUserLinkDirective } from './user-link';
+import { CoreAriaButtonClickDirective } from './aria-button';
@NgModule({
declarations: [
@@ -37,6 +38,7 @@ import { CoreUserLinkDirective } from './user-link';
CoreLongPressDirective,
CoreSupressEventsDirective,
CoreUserLinkDirective,
+ CoreAriaButtonClickDirective,
],
exports: [
CoreAutoFocusDirective,
@@ -49,6 +51,7 @@ import { CoreUserLinkDirective } from './user-link';
CoreLongPressDirective,
CoreSupressEventsDirective,
CoreUserLinkDirective,
+ CoreAriaButtonClickDirective,
],
})
export class CoreDirectivesModule {}