commit
						ae496ef11a
					
				| @ -22,7 +22,7 @@ | ||||
| </ion-item-divider> | ||||
| <core-loading [hideUntil]="loaded" [fullscreen]="false"> | ||||
| 
 | ||||
|     <ion-row class="ion-no-padding ion-justify-content-between" *ngIf="hasCourses"> | ||||
|     <ion-row class="ion-no-padding ion-justify-content-between ion-align-items-center" *ngIf="hasCourses"> | ||||
|         <ion-col size="auto" class="ion-no-padding" *ngIf="filters.enabled"> | ||||
|             <core-combobox interface="modal" [label]="'core.courses.filtermycourses' | translate" (onChange)="filterOptionsChanged($event)" | ||||
|                 icon="fas-filter" [badge]="filters.count" [modalOptions]="filterModalOptions"> | ||||
| @ -48,14 +48,15 @@ | ||||
|                 </ion-select-option> | ||||
|             </core-combobox> | ||||
|         </ion-col> | ||||
|         <ion-col size="auto" class="ion-no-padding" *ngIf="layouts.options.length > 1"> | ||||
|             <!-- "Layouts" selector. --> | ||||
|             <core-combobox [label]="'core.show' | translate" [selection]="layouts.selected" (onChange)="saveLayout($event)" icon="fas-th"> | ||||
|                 <ng-container *ngFor="let layout of layouts.options"> | ||||
|                     <ion-select-option class="ion-text-wrap" [value]="layout">{{ 'addon.block_myoverview.'+layout | translate }} | ||||
|                     </ion-select-option> | ||||
|                 </ng-container> | ||||
|             </core-combobox> | ||||
|         <ion-col size="auto" class="ion-no-padding" *ngIf="isLayoutSwitcherAvailable"> | ||||
|             <ion-button *ngIf="layout == 'card'" fill="outline" (click)="toggleLayout('list')" | ||||
|                 [attr.aria-label]="'addon.block_myoverview.list' | translate"> | ||||
|                 <ion-icon slot="icon-only" name="fas-list"></ion-icon> | ||||
|             </ion-button> | ||||
|             <ion-button *ngIf="layout == 'list'" fill="outline" (click)="toggleLayout('card')" | ||||
|                 [attr.aria-label]="'addon.block_myoverview.card' | translate"> | ||||
|                 <ion-icon slot="icon-only" name="fas-th"></ion-icon> | ||||
|             </ion-button> | ||||
|         </ion-col> | ||||
|     </ion-row> | ||||
|     <ion-row class="ion-no-padding ion-hide-md-up" *ngIf="hasCourses"> | ||||
| @ -73,13 +74,12 @@ | ||||
| 
 | ||||
|     <!-- List of courses. --> | ||||
|     <div class="safe-area-padding" *ngIf="hasCourses"> | ||||
|         <ion-grid class="ion-no-padding" [class.core-no-grid]="layouts.selected != 'card'" | ||||
|             [class.list-item-limited-width]="layouts.selected != 'card'"> | ||||
|         <ion-grid class="ion-no-padding" [class.core-no-grid]="layout != 'card'" [class.list-item-limited-width]="layout != 'card'"> | ||||
|             <ion-row class="ion-no-padding"> | ||||
|                 <ion-col *ngFor="let course of filteredCourses" class="ion-no-padding" size="12" size-sm="6" size-md="6" size-lg="4" | ||||
|                     size-xl="3"> | ||||
|                     <core-courses-course-list-item [course]="course" class="core-courseoverview" [showDownload]="downloadCourseEnabled" | ||||
|                         [layout]="layouts.selected"> | ||||
|                         [layout]="layout"> | ||||
|                     </core-courses-course-list-item> | ||||
|                 </ion-col> | ||||
|             </ion-row> | ||||
|  | ||||
| @ -76,10 +76,8 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem | ||||
|         component: AddonBlockMyOverviewFilterOptionsComponent, | ||||
|     }; | ||||
| 
 | ||||
|     layouts: AddonBlockMyOverviewLayoutOptions = { | ||||
|         options: [], | ||||
|         selected: 'card', | ||||
|     }; | ||||
|     isLayoutSwitcherAvailable = false; | ||||
|     layout: AddonBlockMyOverviewLayouts = 'list'; | ||||
| 
 | ||||
|     sort: AddonBlockMyOverviewSortOptions = { | ||||
|         shortnameEnabled: false, | ||||
| @ -142,9 +140,9 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem | ||||
| 
 | ||||
|         promises.push(this.currentSite.getLocalSiteConfig( | ||||
|             'AddonBlockMyOverviewLayout', | ||||
|             this.layouts.selected, | ||||
|             this.layout, | ||||
|         ).then((value) => { | ||||
|             this.layouts.selected = value; | ||||
|             this.layout = value; | ||||
| 
 | ||||
|             return; | ||||
|         })); | ||||
| @ -340,10 +338,10 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem | ||||
|      * @param layouts Config available layouts. | ||||
|      */ | ||||
|     protected loadLayouts(layouts?: string[]): void { | ||||
|         this.layouts.options = []; | ||||
|         const layoutsOptions: AddonBlockMyOverviewLayouts[] = []; | ||||
| 
 | ||||
|         if (layouts === undefined) { | ||||
|             this.layouts.options = ['card', 'list']; | ||||
|             this.isLayoutSwitcherAvailable = true; | ||||
| 
 | ||||
|             return; | ||||
|         } | ||||
| @ -354,19 +352,21 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem | ||||
|             } | ||||
| 
 | ||||
|             const validLayout: AddonBlockMyOverviewLayouts = layout == 'summary' ? 'list' : layout as AddonBlockMyOverviewLayouts; | ||||
|             if (!this.layouts.options.includes(validLayout)) { | ||||
|                 this.layouts.options.push(validLayout); | ||||
|             if (!layoutsOptions.includes(validLayout)) { | ||||
|                 layoutsOptions.push(validLayout); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         // If no layout is available use card.
 | ||||
|         if (this.layouts.options.length == 0) { | ||||
|             this.layouts.options = ['card']; | ||||
|         // If no layout is available use list.
 | ||||
|         if (layoutsOptions.length == 0) { | ||||
|             layoutsOptions.push('list'); | ||||
|         } | ||||
| 
 | ||||
|         if (!this.layouts.options.includes(this.layouts.selected)) { | ||||
|             this.layouts.selected = this.layouts.options[0]; | ||||
|         if (!layoutsOptions.includes(this.layout)) { | ||||
|             this.layout = layoutsOptions[0]; | ||||
|         } | ||||
| 
 | ||||
|         this.isLayoutSwitcherAvailable = layoutsOptions.length > 1; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -632,15 +632,15 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Saves layout value. | ||||
|      * Toggle layout value. | ||||
|      * | ||||
|      * @param layout New layout. | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     async saveLayout(layout: AddonBlockMyOverviewLayouts): Promise<void> { | ||||
|         this.layouts.selected = layout; | ||||
|     async toggleLayout(layout: AddonBlockMyOverviewLayouts): Promise<void> { | ||||
|         this.layout = layout; | ||||
| 
 | ||||
|         await this.currentSite.setLocalSiteConfig('AddonBlockMyOverviewLayout', this.layouts.selected); | ||||
|         await this.currentSite.setLocalSiteConfig('AddonBlockMyOverviewLayout', this.layout); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -702,11 +702,6 @@ export type AddonBlockMyOverviewFilterOptions = { | ||||
|     count: number; | ||||
| }; | ||||
| 
 | ||||
| type AddonBlockMyOverviewLayoutOptions = { | ||||
|     options: AddonBlockMyOverviewLayouts[]; | ||||
|     selected: AddonBlockMyOverviewLayouts; | ||||
| }; | ||||
| 
 | ||||
| type AddonBlockMyOverviewSortOptions = { | ||||
|     shortnameEnabled: boolean; | ||||
|     selected: string; | ||||
|  | ||||
| @ -549,7 +549,14 @@ export class AddonStorageManagerCourseStoragePage implements OnInit, OnDestroy { | ||||
|      * Prefetch the whole course. | ||||
|      */ | ||||
|     async prefetchCourse(): Promise<void> { | ||||
|         const course = await CoreCourses.getCourse(this.courseId); | ||||
|         const courses = await CoreCourses.getUserCourses(true); | ||||
|         let course = courses.find((course) => course.id == this.courseId); | ||||
|         if (!course) { | ||||
|             course = await CoreCourses.getCourse(this.courseId); | ||||
|         } | ||||
|         if (!course) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         try { | ||||
|             await CoreCourseHelper.confirmAndPrefetchCourse( | ||||
|  | ||||
| @ -20,7 +20,7 @@ | ||||
|                         {{ 'core.settings.spaceusagehelp' | translate }} | ||||
|                     </p> | ||||
|                 </ion-label> | ||||
|                 <ion-button fill="clear" color="danger" slot="end" (click)="deleteSiteStorage()" | ||||
|                 <ion-button fill="clear" color="danger" slot="end" (click)="deleteSiteStorage($event)" | ||||
|                     [hidden]="spaceUsage.spaceUsage! + spaceUsage.cacheEntries! <= 0" | ||||
|                     [attr.aria-label]="'core.settings.deletesitefilestitle' | translate" fill="outline"> | ||||
|                     <ion-icon name="fas-trash" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
| @ -31,8 +31,8 @@ | ||||
|                     <h2 class="ion-text-wrap">{{ 'addon.storagemanager.coursesspaceusage' | translate }}</h2> | ||||
|                     <ion-badge color="light">{{ totalSize | coreBytesToSize }}</ion-badge> | ||||
|                 </ion-label> | ||||
|                 <ion-button slot="end" (click)="deleteCompletelyDownloadedCourses()" [disabled]="completelyDownloadedCourses.length === 0" | ||||
|                     color="danger" fill="outline"> | ||||
|                 <ion-button slot="end" (click)="deleteCompletelyDownloadedCourses($event)" | ||||
|                     [disabled]="completelyDownloadedCourses.length === 0" color="danger" fill="outline"> | ||||
|                     <ion-icon name="fas-trash" slot="icon-only" ariaLabel="{{ 'addon.storagemanager.deletecourses' | translate }}"> | ||||
|                     </ion-icon> | ||||
|                 </ion-button> | ||||
| @ -55,7 +55,8 @@ | ||||
|                                 {{ course.totalSize | coreBytesToSize }} | ||||
|                             </ion-badge> | ||||
|                         </ion-label> | ||||
|                         <ion-button slot="end" (click)="deleteCourse(course)" [disabled]="course.isDownloading" color="danger" fill="clear"> | ||||
|                         <ion-button slot="end" (click)="deleteCourse($event, course)" [disabled]="course.isDownloading" color="danger" | ||||
|                             fill="clear"> | ||||
|                             <ion-icon name="fas-trash" slot="icon-only" | ||||
|                                 [attr.aria-label]="'addon.storagemanager.deletedatafrom' | translate: { name: course.displayname }"> | ||||
|                             </ion-icon> | ||||
|  | ||||
| @ -103,8 +103,13 @@ export class AddonStorageManagerCoursesStoragePage implements OnInit, OnDestroy | ||||
| 
 | ||||
|     /** | ||||
|      * Delete all courses that have been downloaded. | ||||
|      * | ||||
|      * @param event: Event Object. | ||||
|      */ | ||||
|     async deleteCompletelyDownloadedCourses(): Promise<void> { | ||||
|     async deleteCompletelyDownloadedCourses(event: Event): Promise<void> { | ||||
|         event.preventDefault(); | ||||
|         event.stopPropagation(); | ||||
| 
 | ||||
|         try { | ||||
|             await CoreDomUtils.showDeleteConfirm('core.course.confirmdeletestoreddata'); | ||||
|         } catch (error) { | ||||
| @ -132,9 +137,13 @@ export class AddonStorageManagerCoursesStoragePage implements OnInit, OnDestroy | ||||
|     /** | ||||
|      * Delete course. | ||||
|      * | ||||
|      * @param event: Event Object. | ||||
|      * @param course Course to delete. | ||||
|      */ | ||||
|     async deleteCourse(course: DownloadedCourse): Promise<void> { | ||||
|     async deleteCourse(event: Event, course: DownloadedCourse): Promise<void> { | ||||
|         event.preventDefault(); | ||||
|         event.stopPropagation(); | ||||
| 
 | ||||
|         try { | ||||
|             await CoreDomUtils.showDeleteConfirm('core.course.confirmdeletestoreddata'); | ||||
|         } catch (error) { | ||||
| @ -242,9 +251,12 @@ export class AddonStorageManagerCoursesStoragePage implements OnInit, OnDestroy | ||||
|     /** | ||||
|      * Deletes files of a site and the tables that can be cleared. | ||||
|      * | ||||
|      * @param siteData Site object with space usage. | ||||
|      * @param event: Event Object. | ||||
|      */ | ||||
|     async deleteSiteStorage(): Promise<void> { | ||||
|     async deleteSiteStorage(event: Event): Promise<void> { | ||||
|         event.preventDefault(); | ||||
|         event.stopPropagation(); | ||||
| 
 | ||||
|         try { | ||||
|             const siteName = CoreSites.getRequiredCurrentSite().getSiteName(); | ||||
| 
 | ||||
|  | ||||
| @ -55,9 +55,8 @@ ion-button { | ||||
|     color: var(--color); | ||||
|     text-overflow: ellipsis; | ||||
|     white-space: nowrap; | ||||
|     min-height: 26px; | ||||
|     min-height: var(--a11y-min-target-size); | ||||
|     overflow: hidden; | ||||
|     margin: 8px; | ||||
|     box-shadow: var(--box-shadow); | ||||
| 
 | ||||
|     &:focus, | ||||
| @ -71,6 +70,7 @@ ion-select { | ||||
|     border-style: var(--border-style); | ||||
|     border-width: var(--border-width); | ||||
|     border-radius: var(--core-combobox-radius); | ||||
|     margin: 8px; | ||||
| 
 | ||||
|     &::part(icon) { | ||||
|         margin: var(--icon-margin); | ||||
| @ -103,9 +103,9 @@ ion-select { | ||||
| 
 | ||||
| ion-button { | ||||
|     border-radius: var(--core-combobox-radius); | ||||
|     margin: 4px 8px; | ||||
| 
 | ||||
|     flex: 1; | ||||
|     min-height: 45px; | ||||
| 
 | ||||
|     &::part(native) { | ||||
|         text-transform: none; | ||||
|  | ||||
| @ -12,7 +12,7 @@ | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { Component, EventEmitter, Input, Output, ViewChild, ViewEncapsulation } from '@angular/core'; | ||||
| import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core'; | ||||
| import { Translate } from '@singletons'; | ||||
| import { ModalOptions } from '@ionic/core'; | ||||
| import { CoreDomUtils } from '@services/utils/dom'; | ||||
| @ -40,7 +40,6 @@ import { IonSelect } from '@ionic/angular'; | ||||
|     selector: 'core-combobox', | ||||
|     templateUrl: 'core-combobox.html', | ||||
|     styleUrls: ['combobox.scss'], | ||||
|     encapsulation: ViewEncapsulation.ShadowDom, | ||||
| }) | ||||
| export class CoreComboboxComponent { | ||||
| 
 | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| <ion-button (click)="openSelect($event)" color="light" *ngIf="interface != 'modal' && icon" [disabled]="disabled"> | ||||
| <ion-button (click)="openSelect($event)" *ngIf="interface != 'modal' && icon" [disabled]="disabled"> | ||||
|     <ion-icon [name]="icon" [attr.aria-label]="label" slot="start"> | ||||
|     </ion-icon> | ||||
|     <ion-badge *ngIf="badge && badge > 0" slot="start">{{badge}}</ion-badge> | ||||
|  | ||||
| @ -6,12 +6,27 @@ | ||||
|         <img *ngIf="course.courseImage" [src]="course.courseImage" core-external-content alt="" /> | ||||
|         <ion-icon *ngIf="!course.courseImage" name="fas-graduation-cap" class="course-icon"> | ||||
|         </ion-icon> | ||||
|         <ng-container | ||||
|             *ngIf="isEnrolled && ((downloadCourseEnabled && !courseOptionMenuEnabled && showDownload) || courseOptionMenuEnabled)"> | ||||
|             <ng-container *ngTemplateOutlet="download"></ng-container> | ||||
|         </ng-container> | ||||
|     </div> | ||||
| 
 | ||||
|     <ng-container *ngIf="isEnrolled && layout != 'summarycard'"> | ||||
|         <div class="core-button-spinner" *ngIf="!courseOptionMenuEnabled && showDownload"> | ||||
|             <core-download-refresh [status]="prefetchCourseData.status" [enabled]="showDownload" | ||||
|                 [statusTranslatable]="prefetchCourseData.statusTranslatable" [canTrustDownload]="false" | ||||
|                 [loading]="prefetchCourseData.loading" (action)="prefetchCourse()"></core-download-refresh> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="core-button-spinner" *ngIf="courseOptionMenuEnabled"> | ||||
|             <!-- Options menu. --> | ||||
|             <ion-button fill="clear" color="dark" (click)="showCourseOptionsMenu($event)" *ngIf="!showSpinner" | ||||
|                 [attr.aria-label]="('core.displayoptions' | translate)"> | ||||
|                 <ion-icon name="ellipsis-vertical" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|             </ion-button> | ||||
| 
 | ||||
|             <!-- Loading options course spinner. --> | ||||
|             <ion-spinner *ngIf="showSpinner" [attr.aria-label]="'core.loading' | translate"></ion-spinner> | ||||
|         </div> | ||||
|     </ng-container> | ||||
| 
 | ||||
|     <ion-item class="ion-text-wrap" button detail="false" (click)="openCourse()" [attr.aria-label]="course.displayname || course.fullname" | ||||
|         [class.item-disabled]="course.visible == 0"> | ||||
| 
 | ||||
| @ -46,8 +61,8 @@ | ||||
|                         </ion-icon> | ||||
|                     </span> | ||||
| 
 | ||||
|                     <ion-icon *ngIf="downloadCourseEnabled && prefetchCourseData.downloadSucceeded" class="core-icon-downloaded" | ||||
|                         name="cloud-done" color="success" role="status" [attr.aria-label]="'core.downloaded' | translate"></ion-icon> | ||||
|                     <ion-icon *ngIf="prefetchCourseData.downloadSucceeded" class="core-icon-downloaded" name="cloud-done" color="success" | ||||
|                         role="status" [attr.aria-label]="'core.downloaded' | translate"></ion-icon> | ||||
|                 </p> | ||||
| 
 | ||||
|                 <ion-chip color="brand" *ngIf="course.categoryname" | ||||
| @ -63,30 +78,7 @@ | ||||
|                 class="core-course-progress"> | ||||
|                 <core-progress-bar [progress]="progress" a11yText="core.courses.aria:courseprogress"></core-progress-bar> | ||||
|             </div> | ||||
| 
 | ||||
|             <ng-container *ngIf="layout == 'list' || layout == 'listwithenrol' && isEnrolled"> | ||||
|                 <ng-container *ngTemplateOutlet="download"></ng-container> | ||||
|             </ng-container> | ||||
|         </ion-label> | ||||
|     </ion-item> | ||||
| 
 | ||||
| </ion-card> | ||||
| 
 | ||||
| <ng-template #download> | ||||
|     <div class="core-button-spinner" *ngIf="downloadCourseEnabled && !courseOptionMenuEnabled && showDownload"> | ||||
|         <core-download-refresh [status]="prefetchCourseData.status" [enabled]="downloadCourseEnabled" | ||||
|             [statusTranslatable]="prefetchCourseData.statusTranslatable" [canTrustDownload]="false" [loading]="prefetchCourseData.loading" | ||||
|             (action)="prefetchCourse()"></core-download-refresh> | ||||
|     </div> | ||||
| 
 | ||||
|     <div class="core-button-spinner" *ngIf="courseOptionMenuEnabled"> | ||||
|         <!-- Options menu. --> | ||||
|         <ion-button fill="clear" color="dark" (click)="showCourseOptionsMenu($event)" *ngIf="!showSpinner" | ||||
|             [attr.aria-label]="('core.displayoptions' | translate)"> | ||||
|             <ion-icon name="ellipsis-vertical" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|         </ion-button> | ||||
| 
 | ||||
|         <!-- Loading options course spinner. --> | ||||
|         <ion-spinner *ngIf="showSpinner" [attr.aria-label]="'core.loading' | translate"></ion-spinner> | ||||
|     </div> | ||||
| </ng-template> | ||||
|  | ||||
| @ -54,6 +54,7 @@ ion-card { | ||||
|     display: flex; | ||||
|     flex-direction: column; | ||||
|     align-items: center; | ||||
|     z-index: 2; | ||||
| 
 | ||||
|     ion-spinner { | ||||
|         margin-top: 4px; | ||||
| @ -156,7 +157,7 @@ ion-card.core-course-list-card { | ||||
| 
 | ||||
|         ion-icon.course-icon { | ||||
|             color: white; | ||||
|             opacity: 50%; | ||||
|             opacity: 0.5; | ||||
|             position: absolute; | ||||
|             left: 0; | ||||
|             right: 0; | ||||
|  | ||||
| @ -55,7 +55,6 @@ export class CoreCoursesCourseListItemComponent implements OnInit, OnDestroy, On | ||||
|     }; | ||||
| 
 | ||||
|     showSpinner = false; | ||||
|     downloadCourseEnabled = false; | ||||
|     courseOptionMenuEnabled = false; | ||||
|     progress = -1; | ||||
|     completionUserTracked: boolean | undefined = false; | ||||
| @ -63,7 +62,6 @@ export class CoreCoursesCourseListItemComponent implements OnInit, OnDestroy, On | ||||
|     protected courseStatus = CoreConstants.NOT_DOWNLOADED; | ||||
|     protected isDestroyed = false; | ||||
|     protected courseStatusObserver?: CoreEventObserver; | ||||
|     protected siteUpdatedObserver?: CoreEventObserver; | ||||
| 
 | ||||
|     protected element: HTMLElement; | ||||
| 
 | ||||
| @ -93,31 +91,12 @@ export class CoreCoursesCourseListItemComponent implements OnInit, OnDestroy, On | ||||
|         } | ||||
| 
 | ||||
|         if (this.isEnrolled) { | ||||
|             if (this.showDownload) { | ||||
|                 this.initPrefetchCourse(); | ||||
|             } | ||||
| 
 | ||||
|             this.downloadCourseEnabled = !CoreCourses.isDownloadCourseDisabledInSite(); | ||||
| 
 | ||||
|             if (this.downloadCourseEnabled) { | ||||
|                 this.initPrefetchCourse(); | ||||
|             } | ||||
| 
 | ||||
|             // This field is only available from 3.6 onwards.
 | ||||
|             this.courseOptionMenuEnabled = (this.layout != 'listwithenrol' && this.layout != 'summarycard') && | ||||
|                 this.course.isfavourite !== undefined; | ||||
| 
 | ||||
|             // Refresh the enabled flag if site is updated.
 | ||||
|             this.siteUpdatedObserver = CoreEvents.on(CoreEvents.SITE_UPDATED, () => { | ||||
|                 const wasEnabled = this.downloadCourseEnabled; | ||||
|             this.initPrefetchCourse(); | ||||
| 
 | ||||
|                 this.downloadCourseEnabled = !CoreCourses.isDownloadCourseDisabledInSite(); | ||||
| 
 | ||||
|                 if (!wasEnabled && this.downloadCourseEnabled) { | ||||
|                     // Download course is enabled now, initialize it.
 | ||||
|                     this.initPrefetchCourse(); | ||||
|                 } | ||||
|             }, CoreSites.getCurrentSiteId()); | ||||
|         } else if ('enrollmentmethods' in this.course) { | ||||
|             this.enrolmentIcons = []; | ||||
| 
 | ||||
| @ -169,9 +148,7 @@ export class CoreCoursesCourseListItemComponent implements OnInit, OnDestroy, On | ||||
|      * @inheritdoc | ||||
|      */ | ||||
|     ngOnChanges(): void { | ||||
|         if (this.showDownload && this.isEnrolled) { | ||||
|             this.initPrefetchCourse(); | ||||
|         } | ||||
|         this.initPrefetchCourse(); | ||||
| 
 | ||||
|         this.updateCourseFields(); | ||||
|     } | ||||
| @ -203,7 +180,12 @@ export class CoreCoursesCourseListItemComponent implements OnInit, OnDestroy, On | ||||
|     /** | ||||
|      * Initialize prefetch course. | ||||
|      */ | ||||
|     async initPrefetchCourse(): Promise<void> { | ||||
|     async initPrefetchCourse(forceInit = false): Promise<void> { | ||||
|         if (!this.isEnrolled || !this.showDownload || | ||||
|             (this.courseOptionMenuEnabled && !forceInit)) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         if (this.courseStatusObserver !== undefined) { | ||||
|             // Already initialized.
 | ||||
|             return; | ||||
| @ -306,6 +288,8 @@ export class CoreCoursesCourseListItemComponent implements OnInit, OnDestroy, On | ||||
|         event.preventDefault(); | ||||
|         event.stopPropagation(); | ||||
| 
 | ||||
|         this.initPrefetchCourse(true); | ||||
| 
 | ||||
|         const popoverData = await CoreDomUtils.openPopover<string>({ | ||||
|             component: CoreCoursesCourseOptionsMenuComponent, | ||||
|             componentProps: { | ||||
| @ -414,7 +398,6 @@ export class CoreCoursesCourseListItemComponent implements OnInit, OnDestroy, On | ||||
|     ngOnDestroy(): void { | ||||
|         this.isDestroyed = true; | ||||
|         this.courseStatusObserver?.off(); | ||||
|         this.siteUpdatedObserver?.off(); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| :host { | ||||
|     min-height: 61px; | ||||
|     min-height: var(--a11y-min-target-size); | ||||
|     display: block; | ||||
|     position: relative; | ||||
| 
 | ||||
| @ -10,6 +10,10 @@ | ||||
|         z-index: 4; | ||||
|         margin-top: 8px; | ||||
|         margin-bottom: 8px; | ||||
|         --border-color: var(--core-search-box-border-color); | ||||
|         --border-radius: var(--core-search-box-border-radius); | ||||
|         --background: var(--core-search-box-background); | ||||
|         --color: var(--core-search-box-border-color); | ||||
|     } | ||||
| 
 | ||||
|     ion-button.button { | ||||
| @ -19,6 +23,8 @@ | ||||
|     .core-search-history { | ||||
|         max-height: calc(-120px + 80vh); | ||||
|         overflow-y: auto; | ||||
|         background: var(--core-search-box-background); | ||||
|         --ion-item-background: var(--core-search-box-background); | ||||
| 
 | ||||
|         .item:hover { | ||||
|             --background: var(--light); | ||||
| @ -40,5 +46,7 @@ | ||||
| 
 | ||||
|     ion-item { | ||||
|         --min-height: var(--a11y-min-target-size); | ||||
|         --border-width: 0px; | ||||
|         --background: var(--core-search-box-background); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -119,7 +119,7 @@ export class CoreSettingsHelperProvider { | ||||
|         const title = Translate.instant('core.settings.deletesitefilestitle'); | ||||
|         const message = Translate.instant('core.settings.deletesitefiles', { sitename: siteName }); | ||||
| 
 | ||||
|         await CoreDomUtils.showConfirm(message, title); | ||||
|         await CoreDomUtils.showConfirm(message, title, Translate.instant('core.delete')); | ||||
| 
 | ||||
|         const site = await CoreSites.getSite(siteId); | ||||
| 
 | ||||
|  | ||||
| @ -201,6 +201,7 @@ ion-header ion-toolbar { | ||||
|     .in-toolbar.button-clear { | ||||
|         --color: var(--core-header-toolbar-color); | ||||
|         --ion-toolbar-color: var(--core-header-toolbar-color); | ||||
|         --border-radius: var(--huge-radius); | ||||
|     } | ||||
| 
 | ||||
|     .button.button-clear, | ||||
| @ -264,9 +265,15 @@ button, | ||||
|     min-width: var(--a11y-min-target-size); | ||||
| } | ||||
| 
 | ||||
| ion-button { | ||||
|     margin: 4px 8px; | ||||
| } | ||||
| 
 | ||||
| ion-button.button-outline { | ||||
|     --border-width: 1px; | ||||
|     --background: var(--contrast-background); | ||||
|     --border-width: var(--core-input-border-width); | ||||
|     --border-color: var(--core-input-stroke); | ||||
|     --background: var(--core-input-background); | ||||
|     --color: var(--text-color); | ||||
| } | ||||
| 
 | ||||
| ion-button.button-solid { | ||||
| @ -313,12 +320,7 @@ ion-button.button.button-clear.button-has-icon-only { | ||||
| 
 | ||||
| ion-button.button.button-solid, | ||||
| ion-button.button.button-outline { | ||||
|     --border-radius: var(--small-radius); | ||||
| } | ||||
| 
 | ||||
| // Clear buttons will be black. | ||||
| ion-button.button-clear { | ||||
|     --primary: var(--primary); | ||||
|     --border-radius: var(--core-input-radius); | ||||
| } | ||||
| 
 | ||||
| [role="button"], | ||||
|  | ||||
| @ -37,16 +37,19 @@ | ||||
|     --ion-text-color:           var(--text-color); | ||||
|     --ion-text-color-rgb:       #{$text-color-dark-rgb}; | ||||
|     --subdued-text-color:       var(--gray-400); | ||||
|     --stroke:                   var(--gray-700); | ||||
| 
 | ||||
|     --contrast-background: black; | ||||
| 
 | ||||
|     --ion-card-color: var(--text-color); | ||||
|     --ion-card-background: var(--ion-item-background); | ||||
| 
 | ||||
|     --contrast-background: black; | ||||
| 
 | ||||
|     --stroke:           var(--gray-700); | ||||
|     --ion-border-color: var(--stroke); | ||||
|     --ion-item-border-color: var(--stroke); | ||||
| 
 | ||||
|     --core-input-stroke: var(--gray-700); | ||||
|     --core-input-background: var(--gray-900); | ||||
| 
 | ||||
|     ion-content { | ||||
|         --background: var(--ion-background-color); | ||||
|         --background-alternative: var(--gray-900); | ||||
| @ -80,9 +83,18 @@ | ||||
|     --item-divider-color: var(--text-color); | ||||
|     --spacer-background: var(--gray-700); | ||||
| 
 | ||||
|     --core-combobox-background: var(--ion-item-background); | ||||
|     --core-combobox-color: var(--gray-100); | ||||
|     --core-combobox-border-color: var(--stroke); | ||||
|     --ion-searchbar-background: var(--ion-background-color); | ||||
|     --ion-searchbar-border-color: var(--core-input-stroke); | ||||
|     --ion-searchbar-color: var(--text-color); | ||||
|     --ion-searchbar-icon-color: var(--core-input-stroke); | ||||
| 
 | ||||
|     --core-search-box-background: var(--ion-background-color); | ||||
|     --core-search-box-border-color: var(--core-input-stroke); | ||||
|     --core-search-box-color: var(--text-color); | ||||
| 
 | ||||
|     --core-combobox-background: var(--core-input-background); | ||||
|     --core-combobox-color: var(--text-color); | ||||
|     --core-combobox-border-color: var(--core-input-stroke); | ||||
| 
 | ||||
|     --core-login-background: var(--gray-900); | ||||
|     --core-login-text-color: var(--white); | ||||
|  | ||||
| @ -43,40 +43,44 @@ | ||||
|     --ion-color-step-950:  var(--gray-900); | ||||
|     --ion-color-step-1000: var(--black); | ||||
| 
 | ||||
|     --text-color:       #{$text-color}; | ||||
|     --background-color: #{$background-color}; | ||||
| 
 | ||||
|     --core-online-color: #5cb85c; | ||||
| 
 | ||||
|     --stroke:           var(--gray-300); | ||||
|     --ion-border-color: var(--stroke); | ||||
|     --ion-item-border-color: var(--stroke); | ||||
| 
 | ||||
|     @each $color-name, $unused in $colors { | ||||
|         @include generate-color($color-name, $colors); | ||||
|     } | ||||
| 
 | ||||
|     --brand-color: var(--brand); | ||||
| 
 | ||||
|     --small-radius: 4px; | ||||
|     --medium-radius: 8px; | ||||
|     --big-radius: 16px; | ||||
|     --huge-radius: 24px; | ||||
| 
 | ||||
|     // Accessibility vars. | ||||
|     --a11y-min-target-size: 44px; | ||||
|     --a11y-focus-color: var(--primary); | ||||
|     --a11y-focus-width: 2px; | ||||
|     --zoom-level: 100%; | ||||
| 
 | ||||
|     --small-radius: 4px; | ||||
|     --medium-radius: 8px; | ||||
|     --big-radius: 16px; | ||||
|     --huge-radius: 24px; | ||||
| 
 | ||||
|     --text-color:       #{$text-color}; | ||||
|     --background-color: #{$background-color}; | ||||
|     --stroke:            var(--gray-300); | ||||
| 
 | ||||
|     --core-online-color: #5cb85c; | ||||
| 
 | ||||
|     --ion-background-color: var(--background-color); | ||||
|     --ion-item-border-color: var(--stroke); | ||||
|     --ion-background-color-rgb: #{$background-color-rgb}; | ||||
|     --ion-border-color: var(--stroke); | ||||
| 
 | ||||
|     --core-input-stroke: var(--gray-400); | ||||
|     --core-input-background: var(--ion-background-color); | ||||
|     --core-input-radius: var(--small-radius); | ||||
|     --core-input-border-width: 1px; | ||||
| 
 | ||||
|     --module-icon-size: 24px; | ||||
|     --module-icon-radius: var(--medium-radius); | ||||
| 
 | ||||
|     --list-item--max-width: 768px; | ||||
| 
 | ||||
|     --ion-background-color: var(--background-color); | ||||
|     --ion-background-color-rgb: #{$background-color-rgb}; | ||||
| 
 | ||||
|     --contrast-background: white; | ||||
| 
 | ||||
|     --ion-text-color: var(--text-color); | ||||
| @ -155,16 +159,40 @@ | ||||
|         --border-width: 0 0 var(--core-header-toolbar-border-width) 0; | ||||
|     } | ||||
| 
 | ||||
|     --ion-searchbar-background: var(--ion-background-color); | ||||
|     --ion-searchbar-border-color: var(--core-input-stroke); | ||||
|     --ion-searchbar-border-radius: var(--core-input-radius); | ||||
|     --ion-searchbar-color: var(--text-color); | ||||
|     --ion-searchbar-icon-color: var(--core-input-stroke); | ||||
|     ion-searchbar { | ||||
|         --background: var(--ion-item-background); | ||||
|         --background: var(--ion-searchbar-background); | ||||
|         --border-color: var(--ion-searchbar-border-color); | ||||
|         --icon-color: var(--ion-searchbar-icon-color); | ||||
| 
 | ||||
|         .searchbar-input-container { | ||||
|             color: var(--ion-searchbar-color) !important; | ||||
|         } | ||||
|         .searchbar-input { | ||||
|             height: var(--a11y-min-target-size); | ||||
|             border: 1px solid var(--stroke); | ||||
|             border: 1px solid var(--ion-searchbar-border-color); | ||||
|             box-shadow: none; | ||||
|             border-radius: var(--medium-radius); | ||||
|             border-radius: var(--ion-searchbar-border-radius); | ||||
|             background: var(--ion-searchbar-background) !important; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     --core-search-box-background: var(--ion-background-color); | ||||
|     --core-search-box-border-color: var(--core-input-stroke); | ||||
|     --core-search-box-border-radius: var(--core-input-radius); | ||||
|     --core-search-box-color: var(--text-color); | ||||
| 
 | ||||
|     --core-combobox-background: var(--core-input-background); | ||||
|     --core-combobox-color: var(--text-color); | ||||
|     --core-combobox-border-color: var(--core-input-stroke); | ||||
|     --core-combobox-border-width: var(--core-input-border-width); | ||||
|     --core-combobox-radius: var(--core-input-radius); | ||||
|     --core-combobox-box-shadow: none; | ||||
| 
 | ||||
|     ion-action-sheet { | ||||
|         --button-color: var(--ion-text-color); | ||||
|         --button-color-selected: var(--ion-text-color); | ||||
| @ -252,13 +280,6 @@ | ||||
|         --min-width: var(--a11y-min-target-size); | ||||
|     } | ||||
| 
 | ||||
|     --core-combobox-background: var(--ion-item-background); | ||||
|     --core-combobox-color: var(--gray-900); | ||||
|     --core-combobox-border-color: var(--stroke); | ||||
|     --core-combobox-border-width: 1px; | ||||
|     --core-combobox-radius: var(--medium-radius); | ||||
|     --core-combobox-box-shadow: none; | ||||
| 
 | ||||
|     --selected-item-color: var(--primary); | ||||
|     --selected-item-border-width: 5px; | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user