commit
						dab503bb9e
					
				
							
								
								
									
										20
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										20
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -4319,11 +4319,11 @@ | ||||
|       } | ||||
|     }, | ||||
|     "@ionic/angular": { | ||||
|       "version": "5.9.2", | ||||
|       "resolved": "https://registry.npmjs.org/@ionic/angular/-/angular-5.9.2.tgz", | ||||
|       "integrity": "sha512-5GzKg+l4au3xFECky2v/USlRsmTAXgvNO5Zalt7NUXc//VJIL2lQvswojE6FBWuM/xR5W0CWbJdFth19TaZWVQ==", | ||||
|       "version": "5.9.4", | ||||
|       "resolved": "https://registry.npmjs.org/@ionic/angular/-/angular-5.9.4.tgz", | ||||
|       "integrity": "sha512-U/85FePF48VaZXTudTwpVXDqhGmYfarl/7vki7a4umnIORnWtHqD2/pXsqqZ/O1EcbALwULYIeVXAfkFpPd2wQ==", | ||||
|       "requires": { | ||||
|         "@ionic/core": "5.9.2", | ||||
|         "@ionic/core": "5.9.4", | ||||
|         "tslib": "^1.9.3" | ||||
|       }, | ||||
|       "dependencies": { | ||||
| @ -4666,9 +4666,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "@ionic/core": { | ||||
|       "version": "5.9.2", | ||||
|       "resolved": "https://registry.npmjs.org/@ionic/core/-/core-5.9.2.tgz", | ||||
|       "integrity": "sha512-1ZqSBS8R6tGQsc+LsLxIRv0q3Ww6jwgJXLvdn6FmVWfpPbBvT+CjCuU9hqJ5qwM+atErblUMYSexvvpws8lGAA==", | ||||
|       "version": "5.9.4", | ||||
|       "resolved": "https://registry.npmjs.org/@ionic/core/-/core-5.9.4.tgz", | ||||
|       "integrity": "sha512-Ngz9yVT6fIiGdSxxBer8uJxP4w6PasvohYpLxhtMgYiWnyIu0vZra2ui3HrYukCzUo5/SbNPiUr1l7cj1E+7qw==", | ||||
|       "requires": { | ||||
|         "@stencil/core": "^2.4.0", | ||||
|         "ionicons": "^5.5.3", | ||||
| @ -5852,9 +5852,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "@stencil/core": { | ||||
|       "version": "2.11.0", | ||||
|       "resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.11.0.tgz", | ||||
|       "integrity": "sha512-/IubCWhVXCguyMUp/3zGrg3c882+RJNg/zpiKfyfJL3kRCOwe+/MD8OoAXVGdd+xAohZKIi1Ik+EHFlsptsjLg==" | ||||
|       "version": "2.22.2", | ||||
|       "resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.22.2.tgz", | ||||
|       "integrity": "sha512-r+vbxsGNcBaV1VDOYW25lv4QfXTlNoIb5GpUX7rZ+cr59yqYCZC5tlV+IzX6YgHKW62ulCc9M3RYtTfHtNbNNw==" | ||||
|     }, | ||||
|     "@storybook/addon-controls": { | ||||
|       "version": "6.1.21", | ||||
|  | ||||
| @ -73,7 +73,7 @@ | ||||
|     "@ionic-native/status-bar": "5.36.0", | ||||
|     "@ionic-native/web-intent": "5.36.0", | ||||
|     "@ionic-native/zip": "5.36.0", | ||||
|     "@ionic/angular": "5.9.2", | ||||
|     "@ionic/angular": "5.9.4", | ||||
|     "@moodlehq/cordova-plugin-file-opener": "3.0.5-moodle.1", | ||||
|     "@moodlehq/cordova-plugin-file-transfer": "1.7.1-moodle.5", | ||||
|     "@moodlehq/cordova-plugin-inappbrowser": "5.0.0-moodle.3", | ||||
|  | ||||
| @ -33,7 +33,7 @@ | ||||
|         </ion-grid> | ||||
| 
 | ||||
|         <core-swipe-slides [manager]="manager"> | ||||
|             <ng-template let-month="item"> | ||||
|             <ng-template let-month="item" let-activeView="active"> | ||||
|                 <!-- Calendar view. --> | ||||
|                 <ion-grid class="addon-calendar-months" role="table" aria-describedby="addon-calendar-monthname"> | ||||
|                     <div role="rowgroup"> | ||||
| @ -57,9 +57,9 @@ | ||||
|                                     "today": month.isCurrentMonth && day.istoday, | ||||
|                                     "weekend": day.isweekend, | ||||
|                                     "duration_finish": day.haslastdayofevent | ||||
|                                 }' [class.addon-calendar-event-past-day]="month.isPastMonth || day.ispast" role="cell" tabindex="0" | ||||
|                                 (ariaButtonClick)="dayClicked(day.mday)"> | ||||
|                                 <p class="addon-calendar-day-number" role="button"> | ||||
|                                 }' [class.addon-calendar-event-past-day]="month.isPastMonth || day.ispast" role="cell" | ||||
|                                 (ariaButtonClick)="dayClicked(day.mday)" [tabindex]="activeView ? 0 : -1"> | ||||
|                                 <p class="addon-calendar-day-number"> | ||||
|                                     <span aria-hidden="true">{{ day.mday }}</span> | ||||
|                                     <span class="sr-only">{{ day.periodName | translate }}</span> | ||||
|                                 </p> | ||||
| @ -72,8 +72,8 @@ | ||||
|                                 <div class="ion-hide-md-down addon-calendar-day-events" *ngIf="day.filteredEvents"> | ||||
|                                     <ng-container *ngFor="let event of day.filteredEvents | slice:0:4; let index = index"> | ||||
|                                         <div *ngIf="index < 3 || day.filteredEvents.length == 4" class="addon-calendar-event" | ||||
|                                             [class.addon-calendar-event-past]="event.ispast" role="button" tabindex="0" | ||||
|                                             (ariaButtonClick)="eventClicked(event, $event)"> | ||||
|                                             [class.addon-calendar-event-past]="event.ispast" (ariaButtonClick)="eventClicked(event, $event)" | ||||
|                                             [tabindex]="activeView ? 0 : -1"> | ||||
|                                             <span class="calendar_event_type calendar_event_{{event.formattedType}}"></span> | ||||
|                                             <ion-icon *ngIf="event.offline && !event.deleted" name="fas-clock" | ||||
|                                                 [attr.aria-label]="'core.notsent' | translate"></ion-icon> | ||||
|  | ||||
| @ -25,7 +25,6 @@ | ||||
|         @include border-end(1px, solid var(--addon-calendar-border-color)); | ||||
|         overflow: hidden; | ||||
|         min-height: 60px; | ||||
|         cursor: pointer; | ||||
| 
 | ||||
|         &:first-child { | ||||
|             @include padding-horizontal(10px, null); | ||||
|  | ||||
| @ -74,26 +74,20 @@ | ||||
|                 [lines]="discussion.groupname && 'none'" [attr.aria-current]="discussions?.getItemAriaCurrent(discussion)" | ||||
|                 (click)="discussions?.select(discussion)" button> | ||||
|                 <ion-label> | ||||
|                     <div class="addon-mod-forum-discussion-title"> | ||||
|                         <p class="ion-text-wrap item-heading"> | ||||
|                             <ion-icon name="fas-map-pin" *ngIf="discussion.pinned" | ||||
|                                 [attr.aria-label]="'addon.mod_forum.discussionpinned' | translate"></ion-icon> | ||||
|                             <ion-icon name="fas-star" class="addon-forum-star" *ngIf="!discussion.pinned && discussion.starred" | ||||
|                                 [attr.aria-label]="'addon.mod_forum.favourites' | translate"></ion-icon> | ||||
|                             <core-format-text [text]="discussion.subject" contextLevel="module" [contextInstanceId]="module && module.id" | ||||
|                                 [courseId]="courseId"> | ||||
|                             </core-format-text> | ||||
|                             <ion-icon name="fas-lock" *ngIf="discussion.locked" class="addon-mod-forum-locked-icon" | ||||
|                                 [attr.aria-label]="'addon.mod_forum.discussionlocked' | translate"></ion-icon> | ||||
|                         </p> | ||||
|                         <ion-button *ngIf="canPin || discussion.canlock || discussion.canfavourite" fill="clear" | ||||
|                             [attr.aria-label]="('core.displayoptions' | translate)" (click)="showOptionsMenu($event, discussion)"> | ||||
|                             <ion-icon name="ellipsis-vertical" slot="icon-only" aria-hidden="true"> | ||||
|                             </ion-icon> | ||||
|                         </ion-button> | ||||
|                     </div> | ||||
|                     <p class="addon-mod-forum-discussion-title ion-text-wrap item-heading"> | ||||
|                         <ion-icon name="fas-map-pin" *ngIf="discussion.pinned" | ||||
|                             [attr.aria-label]="'addon.mod_forum.discussionpinned' | translate"></ion-icon> | ||||
|                         <ion-icon name="fas-star" class="addon-forum-star" *ngIf="!discussion.pinned && discussion.starred" | ||||
|                             [attr.aria-label]="'addon.mod_forum.favourites' | translate"></ion-icon> | ||||
|                         <core-format-text [text]="discussion.subject" contextLevel="module" [contextInstanceId]="module && module.id" | ||||
|                             [courseId]="courseId"> | ||||
|                         </core-format-text> | ||||
|                         <ion-icon name="fas-lock" *ngIf="discussion.locked" class="addon-mod-forum-locked-icon" | ||||
|                             [attr.aria-label]="'addon.mod_forum.discussionlocked' | translate"></ion-icon> | ||||
|                     </p> | ||||
|                     <div class="addon-mod-forum-discussion-info"> | ||||
|                         <core-user-avatar *ngIf="discussion.userfullname" [user]="discussion" slot="start" [courseId]="courseId"> | ||||
|                         <core-user-avatar *ngIf="discussion.userfullname" [user]="discussion" slot="start" [courseId]="courseId" | ||||
|                             [linkProfile]="false"> | ||||
|                         </core-user-avatar> | ||||
|                         <div class="addon-mod-forum-discussion-author"> | ||||
|                             <span *ngIf="discussion.userfullname">{{discussion.userfullname}}</span> | ||||
| @ -136,6 +130,11 @@ | ||||
|                         </ion-col> | ||||
|                     </ion-row> | ||||
|                 </ion-label> | ||||
|                 <ion-button *ngIf="canPin || discussion.canlock || discussion.canfavourite" fill="clear" | ||||
|                     [attr.aria-label]="('core.displayoptions' | translate)" (click)="showOptionsMenu($event, discussion)" slot="end"> | ||||
|                     <ion-icon name="ellipsis-vertical" slot="icon-only" aria-hidden="true"> | ||||
|                     </ion-icon> | ||||
|                 </ion-button> | ||||
|             </ion-item> | ||||
| 
 | ||||
|             <core-infinite-loading [enabled]="discussions && discussions.loaded && !discussions.completed" [error]="fetchFailed" | ||||
|  | ||||
| @ -7,7 +7,6 @@ | ||||
|     } | ||||
| 
 | ||||
|     .addon-mod-forum-discussion.item { | ||||
| 
 | ||||
|         ion-label { | ||||
|             margin-top: 4px; | ||||
| 
 | ||||
| @ -35,21 +34,30 @@ | ||||
|             @include margin(0, 8px, 0, 0); | ||||
|         } | ||||
| 
 | ||||
|         .addon-mod-forum-discussion-title, | ||||
|         .addon-mod-forum-discussion-info { | ||||
|             display: flex; | ||||
|             align-items: center; | ||||
|         } | ||||
| 
 | ||||
|         .addon-mod-forum-discussion-title .item-heading, | ||||
|         .addon-mod-forum-discussion-info .addon-mod-forum-discussion-author { | ||||
|             flex-grow: 1; | ||||
|         } | ||||
| 
 | ||||
|         .addon-mod-forum-discussion-title { | ||||
|             @include margin-horizontal(null, 8px); | ||||
|             line-height: 18px; | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         .addon-mod-forum-discussion-more-info.ios { | ||||
|             font-size: 0.9rem; | ||||
|         } | ||||
| 
 | ||||
|         ion-button { | ||||
|             position: absolute; | ||||
|             @include position (4px, 8px, null, null); | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     .core-group-selector { | ||||
|  | ||||
| @ -29,19 +29,19 @@ export class CoreAriaRoleTab<T = unknown> { | ||||
|      * @param e Event. | ||||
|      */ | ||||
|     keyDown(tabFindIndex: string, e: KeyboardEvent): void { | ||||
|         if (e.key == ' ' || | ||||
|             e.key == 'Enter' || | ||||
|             e.key == 'Home' || | ||||
|             e.key == 'End' || | ||||
|             (this.isHorizontal() && (e.key == 'ArrowRight' || e.key == 'ArrowLeft')) || | ||||
|             (!this.isHorizontal() && (e.key == 'ArrowUp' ||e.key == 'ArrowDown')) | ||||
|         if (e.key === ' ' || | ||||
|             e.key === 'Enter' || | ||||
|             e.key === 'Home' || | ||||
|             e.key === 'End' || | ||||
|             (this.isHorizontal() && (e.key === 'ArrowRight' || e.key === 'ArrowLeft')) || | ||||
|             (!this.isHorizontal() && (e.key === 'ArrowUp' ||e.key === 'ArrowDown')) | ||||
|         ) { | ||||
|             e.preventDefault(); | ||||
|             e.stopPropagation(); | ||||
|             e.stopImmediatePropagation(); | ||||
|         } | ||||
| 
 | ||||
|         if (e.key == ' ' || e.key == 'Enter') { | ||||
|         if (e.key === ' ' || e.key === 'Enter') { | ||||
|             this.selectTabCandidate = tabFindIndex; | ||||
|         } | ||||
|     } | ||||
| @ -64,7 +64,7 @@ export class CoreAriaRoleTab<T = unknown> { | ||||
|         e.stopPropagation(); | ||||
|         e.stopImmediatePropagation(); | ||||
| 
 | ||||
|         if (e.key == ' ' || e.key == 'Enter') { | ||||
|         if (e.key === ' ' || e.key === 'Enter') { | ||||
|             if (this.selectTabCandidate === tabFindIndex) { | ||||
|                 this.selectTab(tabFindIndex, e); | ||||
|             } | ||||
|  | ||||
| @ -132,7 +132,7 @@ export class CoreShowPasswordComponent implements OnInit, AfterViewInit { | ||||
|      * @param event The mouse event. | ||||
|      */ | ||||
|     doNotBlur(event: Event): void { | ||||
|         if (event.type == 'keydown' && !this.isValidKeyboardKey(<KeyboardEvent>event)) { | ||||
|         if (event.type === 'keydown' && !this.isValidKeyboardKey(<KeyboardEvent>event)) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
| @ -147,7 +147,7 @@ export class CoreShowPasswordComponent implements OnInit, AfterViewInit { | ||||
|      * @returns Wether space or enter have been pressed. | ||||
|      */ | ||||
|     protected isValidKeyboardKey(event: KeyboardEvent): boolean { | ||||
|         return event.key == ' ' || event.key == 'Enter'; | ||||
|         return event.key === ' ' || event.key === 'Enter'; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| <ion-slides *ngIf="loaded" (ionSlideWillChange)="slideWillChange()" (ionSlideDidChange)="slideDidChange()" [options]="options"> | ||||
|     <ion-slide *ngFor="let item of items; index as index"> | ||||
|     <ion-slide *ngFor="let item of items; index as index" [attr.aria-hidden]="!isActive(index)"> | ||||
|         <ng-container *ngIf="template" [ngTemplateOutlet]="template" [ngTemplateOutletContext]="{item: item, active: isActive(index)}"> | ||||
|         </ng-container> | ||||
|     </ion-slide> | ||||
|  | ||||
| @ -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)); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
| @ -32,7 +32,7 @@ | ||||
|                             class="expandable-status-icon" (ariaButtonClick)="toggleExpand($event, section)" | ||||
|                             [attr.aria-label]="(section.expanded ? 'core.collapse' : 'core.expand') | translate" | ||||
|                             [attr.aria-expanded]="section.expanded" [attr.aria-controls]="'core-course-index-section-' + section.id" | ||||
|                             [class.expandable-status-icon-expanded]="section.expanded" tabindex="0"> | ||||
|                             [class.expandable-status-icon-expanded]="section.expanded"> | ||||
|                         </ion-icon> | ||||
|                         <ion-icon *ngIf="!section.hasVisibleModules" name="" slot="start" aria-hidden="true" class="expandable-status-icon"> | ||||
|                         </ion-icon> | ||||
|  | ||||
| @ -1,10 +1,11 @@ | ||||
| <ion-card *ngIf="module.handlerData && module.visibleoncoursepage !== 0" [class.core-course-module-with-view]="moduleHasView"> | ||||
| <ion-card *ngIf="module.handlerData && module.visibleoncoursepage !== 0" [class.core-course-module-with-view]="moduleHasView" | ||||
|     (click)="moduleClicked($event)" [button]="module.handlerData.action && module.uservisible" | ||||
|     [attr.aria-label]="module.handlerData.a11yTitle ? module.handlerData.a11yTitle : null"> | ||||
|     <ng-container *ngIf="!module.handlerData.loading"> | ||||
|         <ion-item id="core-course-module-{{module.id}}" detail="false" | ||||
|             class="ion-text-wrap core-course-module-handler core-module-main-item {{module.handlerData.class}}" | ||||
|             (click)="moduleClicked($event)" [attr.aria-label]="module.handlerData.a11yTitle" [ngClass]="{ | ||||
|         <ion-item id="core-course-module-{{module.id}}" | ||||
|             class="ion-text-wrap core-course-module-handler core-module-main-item {{module.handlerData.class}}" [ngClass]="{ | ||||
|                 'item-dimmed': module.visible === 0 || module.uservisible === false | ||||
|             }" [button]="module.handlerData.action && module.uservisible"> | ||||
|             }"> | ||||
| 
 | ||||
|             <core-mod-icon slot="start" *ngIf="module.handlerData.icon" [modicon]="module.handlerData.icon" [modname]="module.modname" | ||||
|                 [componentId]="module.instance"> | ||||
|  | ||||
| @ -1,8 +1,8 @@ | ||||
| <ion-card [class.core-course-list-item]="layout == 'list' || layout == 'listwithenrol'" | ||||
|     [class.core-course-list-card]="layout == 'card' || layout == 'summarycard'" [class.item-dimmed]="course.hidden"> | ||||
|     [class.core-course-list-card]="layout == 'card' || layout == 'summarycard'" [class.item-dimmed]="course.hidden" (click)="openCourse()" | ||||
|     button [attr.aria-label]="course.displayname || course.fullname"> | ||||
| 
 | ||||
|     <div *ngIf="layout == 'card' || layout == 'summarycard'" (click)="openCourse()" class="core-course-thumb" | ||||
|         [class.core-course-color-img]="course.courseImage"> | ||||
|     <div *ngIf="layout == 'card' || layout == 'summarycard'" class="core-course-thumb" [class.core-course-color-img]="course.courseImage"> | ||||
|         <img *ngIf="course.courseImage" [src]="course.courseImage" core-external-content alt="" /> | ||||
|         <ion-icon *ngIf="!course.courseImage" name="fas-graduation-cap" class="course-icon" aria-hidden="true"> | ||||
|         </ion-icon> | ||||
| @ -27,7 +27,7 @@ | ||||
|         </div> | ||||
|     </ng-container> | ||||
| 
 | ||||
|     <ion-item class="ion-text-wrap" button detail="false" (click)="openCourse()" [attr.aria-label]="course.displayname || course.fullname"> | ||||
|     <ion-item class="ion-text-wrap"> | ||||
| 
 | ||||
|         <ng-container *ngIf="layout == 'list' || layout == 'listwithenrol'"> | ||||
|             <ion-icon *ngIf="!course.courseImage" name="fas-graduation-cap" slot="start" class="course-icon core-course-thumb" | ||||
|  | ||||
| @ -1,38 +1,40 @@ | ||||
| <ion-item button class="ion-text-wrap" (click)="action('download')" *ngIf="downloadCourseEnabled" detail="false"> | ||||
|     <ion-icon *ngIf="!prefetch.loading" [name]="prefetch.icon" slot="start" aria-hidden="true"></ion-icon> | ||||
|     <ion-spinner *ngIf="prefetch.loading" slot="start" [attr.aria-label]="'core.loading' | translate"></ion-spinner> | ||||
|     <ion-label> | ||||
|         <h2>{{ prefetch.statusTranslatable | translate }}</h2> | ||||
|     </ion-label> | ||||
| </ion-item> | ||||
| <ion-item button class="ion-text-wrap" (click)="action('delete')" detail="false" | ||||
|     *ngIf="prefetch.status == 'downloaded' || prefetch.status == 'outdated'"> | ||||
|     <ion-icon name="fas-trash" slot="start" aria-hidden="true"></ion-icon> | ||||
|     <ion-label> | ||||
|         <h2>{{ 'addon.storagemanager.deletedata' | translate }}</h2> | ||||
|     </ion-label> | ||||
| </ion-item> | ||||
| <ion-item button class="ion-text-wrap" (click)="action('hide')" *ngIf="!course.hidden" detail="false"> | ||||
|     <ion-icon name="fas-eye" slot="start" aria-hidden="true"></ion-icon> | ||||
|     <ion-label> | ||||
|         <h2>{{ 'core.courses.hidecourse' | translate }}</h2> | ||||
|     </ion-label> | ||||
| </ion-item> | ||||
| <ion-item button class="ion-text-wrap" (click)="action('show')" *ngIf="course.hidden" detail="false"> | ||||
|     <ion-icon name="fas-eye-slash" slot="start" aria-hidden="true"></ion-icon> | ||||
|     <ion-label> | ||||
|         <h2>{{ 'core.courses.show' | translate }}</h2> | ||||
|     </ion-label> | ||||
| </ion-item> | ||||
| <ion-item button class="ion-text-wrap" (click)="action('favourite')" *ngIf="!course.isfavourite" detail="false"> | ||||
|     <ion-icon name="fas-star" slot="start" aria-hidden="true"></ion-icon> | ||||
|     <ion-label> | ||||
|         <h2>{{ 'core.courses.addtofavourites' | translate }}</h2> | ||||
|     </ion-label> | ||||
| </ion-item> | ||||
| <ion-item button class="ion-text-wrap" (click)="action('unfavourite')" *ngIf="course.isfavourite" detail="false"> | ||||
|     <ion-icon name="far-star" slot="start" aria-hidden="true"></ion-icon> | ||||
|     <ion-label> | ||||
|         <h2>{{ 'core.courses.removefromfavourites' | translate }}</h2> | ||||
|     </ion-label> | ||||
| </ion-item> | ||||
| <ion-list> | ||||
|     <ion-item button class="ion-text-wrap" (click)="action('download')" *ngIf="downloadCourseEnabled" detail="false"> | ||||
|         <ion-icon *ngIf="!prefetch.loading" [name]="prefetch.icon" slot="start" aria-hidden="true"></ion-icon> | ||||
|         <ion-spinner *ngIf="prefetch.loading" slot="start" [attr.aria-label]="'core.loading' | translate"></ion-spinner> | ||||
|         <ion-label> | ||||
|             <p class="item-heading">{{ prefetch.statusTranslatable | translate }}</p> | ||||
|         </ion-label> | ||||
|     </ion-item> | ||||
|     <ion-item button class="ion-text-wrap" (click)="action('delete')" detail="false" | ||||
|         *ngIf="prefetch.status == 'downloaded' || prefetch.status == 'outdated'"> | ||||
|         <ion-icon name="fas-trash" slot="start" aria-hidden="true"></ion-icon> | ||||
|         <ion-label> | ||||
|             <p class="item-heading">{{ 'addon.storagemanager.deletedata' | translate }}</p> | ||||
|         </ion-label> | ||||
|     </ion-item> | ||||
|     <ion-item button class="ion-text-wrap" (click)="action('hide')" *ngIf="!course.hidden" detail="false"> | ||||
|         <ion-icon name="fas-eye" slot="start" aria-hidden="true"></ion-icon> | ||||
|         <ion-label> | ||||
|             <p class="item-heading">{{ 'core.courses.hidecourse' | translate }}</p> | ||||
|         </ion-label> | ||||
|     </ion-item> | ||||
|     <ion-item button class="ion-text-wrap" (click)="action('show')" *ngIf="course.hidden" detail="false"> | ||||
|         <ion-icon name="fas-eye-slash" slot="start" aria-hidden="true"></ion-icon> | ||||
|         <ion-label> | ||||
|             <p class="item-heading">{{ 'core.courses.show' | translate }}</p> | ||||
|         </ion-label> | ||||
|     </ion-item> | ||||
|     <ion-item button class="ion-text-wrap" (click)="action('favourite')" *ngIf="!course.isfavourite" detail="false"> | ||||
|         <ion-icon name="fas-star" slot="start" aria-hidden="true"></ion-icon> | ||||
|         <ion-label> | ||||
|             <p class="item-heading">{{ 'core.courses.addtofavourites' | translate }}</p> | ||||
|         </ion-label> | ||||
|     </ion-item> | ||||
|     <ion-item button class="ion-text-wrap" (click)="action('unfavourite')" *ngIf="course.isfavourite" detail="false"> | ||||
|         <ion-icon name="far-star" slot="start" aria-hidden="true"></ion-icon> | ||||
|         <ion-label> | ||||
|             <p class="item-heading">{{ 'core.courses.removefromfavourites' | translate }}</p> | ||||
|         </ion-label> | ||||
|     </ion-item> | ||||
| </ion-list> | ||||
|  | ||||
| @ -15,9 +15,9 @@ | ||||
| </div> | ||||
| 
 | ||||
| <div #toolbar class="core-rte-toolbar" [class.toolbar-hidden]="toolbarHidden"> | ||||
|     <button *ngIf="toolbarArrows" class="toolbar-arrow" [class.toolbar-arrow-hidden]="toolbarPrevHidden" (click)="toolbarPrev($event)" | ||||
|     <button *ngIf="toolbarArrows" class="toolbar-arrow" [attr.disabled]="toolbarPrevHidden ? 'true' : null" (click)="toolbarPrev($event)" | ||||
|         (keyup)="toolbarPrev($event)" (mousedown)="downAction($event)" (keydown)="downAction($event)" | ||||
|         [attr.aria-label]="'core.previous' | translate"> | ||||
|         [attr.aria-label]="'core.previous' | translate" [tabindex]="toolbarPrevHidden ? -1 : 0"> | ||||
|         <ion-icon name="fas-chevron-left" aria-hidden="true"></ion-icon> | ||||
|     </button> | ||||
|     <ion-slides [options]="slidesOpts" [dir]="direction" (ionSlideDidChange)="updateToolbarArrows()"> | ||||
| @ -25,69 +25,70 @@ | ||||
|         <ion-slide> | ||||
|             <button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.strong" [title]="'core.editor.bold' | translate" | ||||
|                 (click)="buttonAction($event, 'bold', 'strong')" (keyup)="buttonAction($event, 'bold', 'strong')" | ||||
|                 (mousedown)="downAction($event)" (keydown)="downAction($event)"> | ||||
|                 (mousedown)="downAction($event)" (keydown)="downAction($event)" tabindex="0"> | ||||
|                 <ion-icon name="fas-bold" aria-hidden="true"></ion-icon> | ||||
|             </button> | ||||
|         </ion-slide> | ||||
|         <ion-slide> | ||||
|             <button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.em" [title]="'core.editor.italic' | translate" | ||||
|                 (click)="buttonAction($event, 'italic', 'em')" (keyup)="buttonAction($event, 'italic', 'em')" | ||||
|                 (mousedown)="downAction($event)" (keydown)="downAction($event)"> | ||||
|                 (mousedown)="downAction($event)" (keydown)="downAction($event)" tabindex="0"> | ||||
|                 <ion-icon name="fas-italic" aria-hidden="true"></ion-icon> | ||||
|             </button> | ||||
|         </ion-slide> | ||||
|         <ion-slide> | ||||
|             <button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.u" [title]="'core.editor.underline' | translate" | ||||
|                 (click)="buttonAction($event, 'underline', 'u')" (keyup)="buttonAction($event, 'underline', 'u')" | ||||
|                 (mousedown)="downAction($event)" (keydown)="downAction($event)"> | ||||
|                 (mousedown)="downAction($event)" (keydown)="downAction($event)" tabindex="0"> | ||||
|                 <ion-icon name="fas-underline" aria-hidden="true"></ion-icon> | ||||
|             </button> | ||||
|         </ion-slide> | ||||
|         <ion-slide> | ||||
|             <button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.strike" [title]="'core.editor.strike' | translate" | ||||
|                 (click)="buttonAction($event, 'strikethrough', 'strike')" (keyup)="buttonAction($event, 'strikethrough', 'strike')" | ||||
|                 (mousedown)="downAction($event)" (keydown)="downAction($event)"> | ||||
|                 (mousedown)="downAction($event)" (keydown)="downAction($event)" tabindex="0"> | ||||
|                 <ion-icon name="fas-strikethrough" aria-hidden="true"></ion-icon> | ||||
|             </button> | ||||
|         </ion-slide> | ||||
|         <ion-slide> | ||||
|             <button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.p" [title]="'core.editor.p' | translate" | ||||
|                 (click)="buttonAction($event, 'p', 'block')" (keyup)="buttonAction($event, 'p', 'block')" (mousedown)="downAction($event)" | ||||
|                 (keydown)="downAction($event)"> | ||||
|                 (keydown)="downAction($event)" tabindex="0"> | ||||
|                 <ion-icon name="fas-paragraph" aria-hidden="true"></ion-icon> | ||||
|             </button> | ||||
|         </ion-slide> | ||||
|         <ion-slide> | ||||
|             <button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.h3" [title]="'core.editor.h3' | translate" | ||||
|                 (click)="buttonAction($event, 'h3', 'block')" (keyup)="buttonAction($event, 'h3', 'block')" (mousedown)="downAction($event)" | ||||
|                 (keydown)="downAction($event)"> | ||||
|                 (keydown)="downAction($event)" tabindex="0"> | ||||
|                 <ion-icon name="fas-heading" aria-hidden="true"></ion-icon><span aria-hidden="true">3</span> | ||||
|             </button> | ||||
|         </ion-slide> | ||||
|         <ion-slide> | ||||
|             <button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.h4" [title]="'core.editor.h4' | translate" | ||||
|                 (click)="buttonAction($event, 'h4', 'block')" (keyup)="buttonAction($event, 'h4', 'block')" (mousedown)="downAction($event)" | ||||
|                 (keydown)="downAction($event)"> | ||||
|                 (keydown)="downAction($event)" tabindex="0"> | ||||
|                 <ion-icon name="fas-heading" aria-hidden="true"></ion-icon><span aria-hidden="true">4</span> | ||||
|             </button> | ||||
|         </ion-slide> | ||||
|         <ion-slide> | ||||
|             <button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.h5" [title]="'core.editor.h5' | translate" | ||||
|                 (click)="buttonAction($event, 'h5', 'block')" (keyup)="buttonAction($event, 'h5', 'block')" (mousedown)="downAction($event)" | ||||
|                 (keydown)="downAction($event)"> | ||||
|                 (keydown)="downAction($event)" tabindex="0"> | ||||
|                 <ion-icon name="fas-heading" aria-hidden="true"></ion-icon><span aria-hidden="true">5</span> | ||||
|             </button> | ||||
|         </ion-slide> | ||||
|         <ion-slide> | ||||
|             <button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.ul" [title]="'core.editor.unorderedlist' | translate" | ||||
|                 (click)="buttonAction($event, 'insertUnorderedList')" (mousedown)="downAction($event)" (keydown)="downAction($event)"> | ||||
|                 (click)="buttonAction($event, 'insertUnorderedList')" (mousedown)="downAction($event)" (keydown)="downAction($event)" | ||||
|                 tabindex="0"> | ||||
|                 <ion-icon name="fas-list-ul" aria-hidden="true"></ion-icon> | ||||
|             </button> | ||||
|         </ion-slide> | ||||
|         <ion-slide> | ||||
|             <button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.ol" [title]="'core.editor.orderedlist' | translate" | ||||
|                 (click)="buttonAction($event, 'insertOrderedList')" (keyup)="buttonAction($event, 'insertOrderedList')" | ||||
|                 (mousedown)="downAction($event)" (keydown)="downAction($event)"> | ||||
|                 (mousedown)="downAction($event)" (keydown)="downAction($event)" tabindex="0"> | ||||
|                 <ion-icon name="fas-list-ol" aria-hidden="true"></ion-icon> | ||||
|             </button> | ||||
|         </ion-slide> | ||||
| @ -105,20 +106,20 @@ | ||||
|         </ion-slide> | ||||
|         <ion-slide> | ||||
|             <button [attr.aria-pressed]="!rteEnabled" [title]="'core.editor.toggle' | translate" (click)="toggleEditor($event)" | ||||
|                 (keyup)="toggleEditor($event)" (mousedown)="downAction($event)" (keydown)="downAction($event)"> | ||||
|                 (keyup)="toggleEditor($event)" (mousedown)="downAction($event)" (keydown)="downAction($event)" tabindex="0"> | ||||
|                 <ion-icon name="fas-code" aria-hidden="true"></ion-icon> | ||||
|             </button> | ||||
|         </ion-slide> | ||||
|         <ion-slide *ngIf="isPhone"> | ||||
|             <button [title]="'core.editor.hidetoolbar' | translate" (click)="hideToolbar($event, true)" (keyup)="hideToolbar($event, true)" | ||||
|                 (mousedown)="downAction($event)" (keydown)="downAction($event)"> | ||||
|                 (mousedown)="downAction($event)" (keydown)="downAction($event)" tabindex="0"> | ||||
|                 <ion-icon name="fas-times" aria-hidden="true"></ion-icon> | ||||
|             </button> | ||||
|         </ion-slide> | ||||
|     </ion-slides> | ||||
|     <button *ngIf="toolbarArrows" class="toolbar-arrow" [class.toolbar-arrow-hidden]="toolbarNextHidden" | ||||
|     <button *ngIf="toolbarArrows" class="toolbar-arrow" [attr.disabled]="toolbarNextHidden ? 'true' : null" | ||||
|         [attr.aria-label]="'core.next' | translate" (click)="toolbarNext($event)" (keyup)="toolbarNext($event)" | ||||
|         (mousedown)="downAction($event)" (keydown)="downAction($event)"> | ||||
|         (mousedown)="downAction($event)" (keydown)="downAction($event)" [tabindex]="toolbarNextHidden ? -1 : 0"> | ||||
|         <ion-icon name="fas-chevron-right" aria-hidden="true"></ion-icon> | ||||
|     </button> | ||||
| </div> | ||||
|  | ||||
| @ -149,8 +149,9 @@ | ||||
|                     background-color: var(--toobar-background); | ||||
|                 } | ||||
| 
 | ||||
|                 &.toolbar-arrow-hidden { | ||||
|                     opacity: 0; | ||||
|                 &[disabled], | ||||
|                 &:disabled { | ||||
|                     opacity: .5; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @ -391,7 +391,7 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterViewInit, | ||||
| 
 | ||||
|         this.stopBubble(event); | ||||
| 
 | ||||
|         const move = event.key == 'ArrowLeft' ? -1 : +1; | ||||
|         const move = event.key === 'ArrowLeft' ? -1 : +1; | ||||
|         const cursor = this.getCurrentCursorPosition(this.editorElement); | ||||
| 
 | ||||
|         this.setCurrentCursorPosition(this.editorElement, cursor + move); | ||||
| @ -754,7 +754,7 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterViewInit, | ||||
|      * @returns Wether space or enter have been pressed. | ||||
|      */ | ||||
|     protected isValidKeyboardKey(event: KeyboardEvent): boolean { | ||||
|         return event.key == ' ' || event.key == 'Enter'; | ||||
|         return event.key === ' ' || event.key === 'Enter'; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
| @ -353,7 +353,7 @@ export class CoreLoginReconnectPage implements OnInit, OnDestroy { | ||||
|      * @param e Event. | ||||
|      */ | ||||
|     keyDown(e: KeyboardEvent): void { | ||||
|         if (e.key == 'Escape') { | ||||
|         if (e.key === 'Escape') { | ||||
|             e.preventDefault(); | ||||
|             e.stopPropagation(); | ||||
|         } | ||||
| @ -365,7 +365,7 @@ export class CoreLoginReconnectPage implements OnInit, OnDestroy { | ||||
|      * @param e Event. | ||||
|      */ | ||||
|     keyUp(e: KeyboardEvent): void { | ||||
|         if (e.key == 'Escape') { | ||||
|         if (e.key === 'Escape') { | ||||
|             this.cancel(e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -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,22 +514,57 @@ 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) => { | ||||
|             if ((event.key == ' ' || event.key == 'Enter')) { | ||||
|             if (event.key === ' ' || event.key === 'Enter') { | ||||
|                 event.preventDefault(); | ||||
|                 event.stopPropagation(); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         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'); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -81,6 +81,7 @@ | ||||
| 
 | ||||
| @mixin core-focus-style() { | ||||
|     box-shadow: inset 0 0 var(--a11y-focus-width) 1px var(--a11y-focus-color); | ||||
|     border-radius: var(--border-radius); | ||||
|     // Thicker option: | ||||
|     // border: var(--a11y-focus-width) solid var(--a11y-focus-color); | ||||
| } | ||||
|  | ||||
| @ -897,12 +897,16 @@ img[core-external-content]:not([src]) { | ||||
| } | ||||
| 
 | ||||
| ion-card { | ||||
|     box-shadow: var(--box-shadow); | ||||
|     margin: var(--ion-card-vertical-margin) var(--ion-card-horizontal-margin); | ||||
|     border-width: var(--border-width); | ||||
|     border-style: var(--border-style); | ||||
|     border-color: var(--border-color); | ||||
|     box-shadow: var(--box-shadow); | ||||
|     border-radius: var(--border-radius); | ||||
|     margin: var(--ion-card-vertical-margin) var(--ion-card-horizontal-margin); | ||||
| 
 | ||||
|     &::part(native) { | ||||
|         --border-width: 0; | ||||
|     } | ||||
| 
 | ||||
|     ion-item:only-child { | ||||
|         --inner-border-width: 0px; | ||||
| @ -1514,19 +1518,24 @@ ion-item.item-input.item-multiple-inputs { | ||||
| } | ||||
| 
 | ||||
| // Focus highlight for accessibility. | ||||
| ion-item.item-input.ion-focused:not(:focus), | ||||
| .ion-focused, | ||||
| ion-item.ion-activatable.ion-focused:not(:focus), | ||||
| .ion-focused:not(.item-multiple-inputs):not(:focus), | ||||
| ion-input.has-focus, | ||||
| .ion-focused ion-toggle:focus-within, | ||||
| .ion-focused ion-select:focus-within, | ||||
| .ion-focused ion-checkbox:focus-within, | ||||
| .ion-focused ion-radio:focus-within { | ||||
| ion-card:focus { | ||||
|     @include core-focus(); | ||||
| } | ||||
| .ion-focused.item-multiple-inputs, | ||||
| .ion-focused.ion-activatable { | ||||
|     ion-toggle:focus-within, | ||||
|     ion-select:focus-within, | ||||
|     ion-checkbox:focus-within, | ||||
|     ion-radio:focus-within { | ||||
|         @include core-focus(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // Treat cases where there's a focusable element inside an item, like a button. | ||||
| ion-item.ion-focused:not(:focus), | ||||
| ion-item.item-input:not(.item-multiple-inputs):not(:focus), | ||||
| ion-item.item-has-focus:not(.item-multiple-inputs):not(:focus), | ||||
| ion-item.item-input ion-input.has-focus { | ||||
|     position: relative; | ||||
|     &::after { | ||||
| @ -1576,13 +1585,17 @@ ion-item.item { | ||||
|     outline: none; | ||||
| } | ||||
| 
 | ||||
| textarea, button, select, input, a { | ||||
| textarea, button, select, input, a, .clickable { | ||||
|     &:focus { | ||||
|         @include core-focus-style(); | ||||
|         outline: none; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| .ion-focused:not(.item-multiple-inputs):not(:focus) .clickable:focus { | ||||
|     box-shadow: none; | ||||
| } | ||||
| 
 | ||||
| ion-loading:focus-visible, | ||||
| ion-alert:focus-visible, | ||||
| ion-popover:focus-visible, | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user