forked from EVOgeek/Vmeda.Online
		
	
						commit
						8471b549d1
					
				| @ -6,9 +6,11 @@ | |||||||
|         <div *ngFor="let item of items"> |         <div *ngFor="let item of items"> | ||||||
|             <ion-card> |             <ion-card> | ||||||
|                 <ion-item class="core-course-module-handler item-media ion-text-wrap" detail="false" (click)="action($event, item)" |                 <ion-item class="core-course-module-handler item-media ion-text-wrap" detail="false" (click)="action($event, item)" | ||||||
|                     [title]="item.name" button> |                     button> | ||||||
|                     <img slot="start" [src]="item.iconUrl" alt="" role="presentation" *ngIf="item.iconUrl" class="core-module-icon"> |                     <img slot="start" [src]="item.iconUrl" alt="" role="presentation" *ngIf="item.iconUrl" class="core-module-icon"> | ||||||
|                     <ion-label> |                     <ion-label> | ||||||
|  |                         <!-- Add the icon title so accessibility tools read it. --> | ||||||
|  |                         <span class="sr-only" *ngIf="item.iconTitle">{{ item.iconTitle }}</span> | ||||||
|                         <h2> |                         <h2> | ||||||
|                             <core-format-text [text]="item.name" contextLevel="module" [contextInstanceId]="item.cmid" |                             <core-format-text [text]="item.name" contextLevel="module" [contextInstanceId]="item.cmid" | ||||||
|                                 [courseId]="item.courseid"></core-format-text> |                                 [courseId]="item.courseid"></core-format-text> | ||||||
|  | |||||||
| @ -56,6 +56,7 @@ export class AddonBlockRecentlyAccessedItemsProvider { | |||||||
|             const modicon = item.icon && CoreDomUtils.getHTMLElementAttribute(item.icon, 'src'); |             const modicon = item.icon && CoreDomUtils.getHTMLElementAttribute(item.icon, 'src'); | ||||||
| 
 | 
 | ||||||
|             item.iconUrl = CoreCourse.getModuleIconSrc(item.modname, modicon || undefined); |             item.iconUrl = CoreCourse.getModuleIconSrc(item.modname, modicon || undefined); | ||||||
|  |             item.iconTitle = item.icon && CoreDomUtils.getHTMLElementAttribute(item.icon, 'title'); | ||||||
| 
 | 
 | ||||||
|             return item; |             return item; | ||||||
|         }); |         }); | ||||||
| @ -99,4 +100,5 @@ export type AddonBlockRecentlyAccessedItemsItem = { | |||||||
|  */ |  */ | ||||||
| export type AddonBlockRecentlyAccessedItemsItemCalculatedData = { | export type AddonBlockRecentlyAccessedItemsItemCalculatedData = { | ||||||
|     iconUrl: string; // Icon URL. Calculated by the app.
 |     iconUrl: string; // Icon URL. Calculated by the app.
 | ||||||
|  |     iconTitle?: string | null; // Icon title.
 | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -58,7 +58,7 @@ | |||||||
|                             <ion-label position="stacked">{{ 'addon.mod_lesson.enterpassword' | translate }}</ion-label> |                             <ion-label position="stacked">{{ 'addon.mod_lesson.enterpassword' | translate }}</ion-label> | ||||||
|                             <core-show-password name="password"> |                             <core-show-password name="password"> | ||||||
|                                 <ion-input name="password" type="password" placeholder="{{ 'core.login.password' | translate }}" |                                 <ion-input name="password" type="password" placeholder="{{ 'core.login.password' | translate }}" | ||||||
|                                     [core-auto-focus] #passwordinput [clearOnEdit]="false"> |                                     [autofocus]="true" #passwordinput [clearOnEdit]="false"> | ||||||
|                                 </ion-input> |                                 </ion-input> | ||||||
|                             </core-show-password> |                             </core-show-password> | ||||||
|                         </ion-item> |                         </ion-item> | ||||||
|  | |||||||
| @ -424,7 +424,7 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo | |||||||
|             pageId = continueLast ? this.accessInfo.lastpageseen : this.accessInfo.firstpageid; |             pageId = continueLast ? this.accessInfo.lastpageseen : this.accessInfo.firstpageid; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         await CoreNavigator.navigate(`../player/${this.courseId}/${this.lesson.id}`, { |         await CoreNavigator.navigate('player', { | ||||||
|             params: { |             params: { | ||||||
|                 pageId: pageId, |                 pageId: pageId, | ||||||
|                 password: this.password, |                 password: this.password, | ||||||
| @ -472,7 +472,7 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         CoreNavigator.navigate(`../player/${this.courseId}/${this.lesson.id}`, { |         CoreNavigator.navigate('player', { | ||||||
|             params: { |             params: { | ||||||
|                 pageId: this.retakeToReview.pageid, |                 pageId: this.retakeToReview.pageid, | ||||||
|                 password: this.password, |                 password: this.password, | ||||||
| @ -695,7 +695,7 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo | |||||||
|      * @return Promise resolved when done. |      * @return Promise resolved when done. | ||||||
|      */ |      */ | ||||||
|     async openRetake(userId: number): Promise<void> { |     async openRetake(userId: number): Promise<void> { | ||||||
|         await CoreNavigator.navigate(`../user-retake/${this.courseId}/${this.lesson!.id}`, { |         await CoreNavigator.navigate('user-retake', { | ||||||
|             params: { |             params: { | ||||||
|                 userId, |                 userId, | ||||||
|             }, |             }, | ||||||
|  | |||||||
| @ -15,7 +15,8 @@ | |||||||
|             <ion-label>{{ 'addon.mod_lesson.enterpassword' | translate }}</ion-label> |             <ion-label>{{ 'addon.mod_lesson.enterpassword' | translate }}</ion-label> | ||||||
|             <core-show-password name="password"> |             <core-show-password name="password"> | ||||||
|                 <ion-input name="password" type="password" placeholder="{{ 'core.login.password' | translate }}" |                 <ion-input name="password" type="password" placeholder="{{ 'core.login.password' | translate }}" | ||||||
|                     [core-auto-focus] #passwordinput [clearOnEdit]="false"></ion-input> |                     [autofocus]="true" #passwordinput [clearOnEdit]="false"> | ||||||
|  |                 </ion-input> | ||||||
|             </core-show-password> |             </core-show-password> | ||||||
|         </ion-item> |         </ion-item> | ||||||
|         <ion-button expand="block" type="submit"> |         <ion-button expand="block" type="submit"> | ||||||
|  | |||||||
| @ -26,11 +26,11 @@ const routes: Routes = [ | |||||||
|         component: AddonModLessonIndexPage, |         component: AddonModLessonIndexPage, | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|         path: 'player/:courseId/:lessonId', |         path: ':courseId/:cmId/player', | ||||||
|         loadChildren: () => import('./pages/player/player.module').then( m => m.AddonModLessonPlayerPageModule), |         loadChildren: () => import('./pages/player/player.module').then( m => m.AddonModLessonPlayerPageModule), | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|         path: 'user-retake/:courseId/:lessonId', |         path: ':courseId/:cmId/user-retake', | ||||||
|         loadChildren: () => import('./pages/user-retake/user-retake.module').then( m => m.AddonModLessonUserRetakePageModule), |         loadChildren: () => import('./pages/user-retake/user-retake.module').then( m => m.AddonModLessonUserRetakePageModule), | ||||||
|     }, |     }, | ||||||
| ]; | ]; | ||||||
|  | |||||||
| @ -98,7 +98,7 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy, CanLeave { | |||||||
|     mediaFile?: CoreWSExternalFile; // Media file of the lesson.
 |     mediaFile?: CoreWSExternalFile; // Media file of the lesson.
 | ||||||
|     activityLink?: AddonModLessonActivityLink; // Next activity link data.
 |     activityLink?: AddonModLessonActivityLink; // Next activity link data.
 | ||||||
| 
 | 
 | ||||||
|     protected lessonId!: number; // Lesson ID.
 |     protected cmId!: number; // Course module ID.
 | ||||||
|     protected password?: string; // Lesson password (if any).
 |     protected password?: string; // Lesson password (if any).
 | ||||||
|     protected forceLeave = false; // If true, don't perform any check when leaving the view.
 |     protected forceLeave = false; // If true, don't perform any check when leaving the view.
 | ||||||
|     protected offline?: boolean; // Whether we are in offline mode.
 |     protected offline?: boolean; // Whether we are in offline mode.
 | ||||||
| @ -118,22 +118,19 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy, CanLeave { | |||||||
|      * Component being initialized. |      * Component being initialized. | ||||||
|      */ |      */ | ||||||
|     async ngOnInit(): Promise<void> { |     async ngOnInit(): Promise<void> { | ||||||
|         this.lessonId = CoreNavigator.getRouteNumberParam('lessonId')!; |         this.cmId = CoreNavigator.getRouteNumberParam('cmId')!; | ||||||
|         this.courseId = CoreNavigator.getRouteNumberParam('courseId')!; |         this.courseId = CoreNavigator.getRouteNumberParam('courseId')!; | ||||||
|         this.password = CoreNavigator.getRouteParam('password'); |         this.password = CoreNavigator.getRouteParam('password'); | ||||||
|         this.review = !!CoreNavigator.getRouteBooleanParam('review'); |         this.review = !!CoreNavigator.getRouteBooleanParam('review'); | ||||||
|         this.currentPage = CoreNavigator.getRouteNumberParam('pageId'); |         this.currentPage = CoreNavigator.getRouteNumberParam('pageId'); | ||||||
|         this.retakeToReview = CoreNavigator.getRouteNumberParam('retake'); |         this.retakeToReview = CoreNavigator.getRouteNumberParam('retake'); | ||||||
| 
 | 
 | ||||||
|         // Block the lesson so it cannot be synced.
 |  | ||||||
|         CoreSync.blockOperation(this.component, this.lessonId); |  | ||||||
| 
 |  | ||||||
|         try { |         try { | ||||||
|             // Fetch the Lesson data.
 |             // Fetch the Lesson data.
 | ||||||
|             const success = await this.fetchLessonData(); |             const success = await this.fetchLessonData(); | ||||||
|             if (success) { |             if (success) { | ||||||
|                 // Review data loaded or new retake started, remove any retake being finished in sync.
 |                 // Review data loaded or new retake started, remove any retake being finished in sync.
 | ||||||
|                 AddonModLessonSync.deleteRetakeFinishedInSync(this.lessonId); |                 AddonModLessonSync.deleteRetakeFinishedInSync(this.lesson!.id); | ||||||
|             } |             } | ||||||
|         } finally { |         } finally { | ||||||
|             this.loaded = true; |             this.loaded = true; | ||||||
| @ -144,8 +141,10 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy, CanLeave { | |||||||
|      * Component being destroyed. |      * Component being destroyed. | ||||||
|      */ |      */ | ||||||
|     ngOnDestroy(): void { |     ngOnDestroy(): void { | ||||||
|         // Unblock the lesson so it can be synced.
 |         if (this.lesson) { | ||||||
|         CoreSync.unblockOperation(this.component, this.lessonId); |             // Unblock the lesson so it can be synced.
 | ||||||
|  |             CoreSync.unblockOperation(this.component, this.lesson.id); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -214,7 +213,7 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy, CanLeave { | |||||||
| 
 | 
 | ||||||
|             // Get the possible jumps now.
 |             // Get the possible jumps now.
 | ||||||
|             this.jumps = await AddonModLesson.getPagesPossibleJumps(this.lesson!.id, { |             this.jumps = await AddonModLesson.getPagesPossibleJumps(this.lesson!.id, { | ||||||
|                 cmId: this.lesson!.coursemodule, |                 cmId: this.cmId, | ||||||
|                 readingStrategy: CoreSitesReadingStrategy.PreferCache, |                 readingStrategy: CoreSitesReadingStrategy.PreferCache, | ||||||
|             }); |             }); | ||||||
| 
 | 
 | ||||||
| @ -259,14 +258,18 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy, CanLeave { | |||||||
|      */ |      */ | ||||||
|     protected async fetchLessonData(): Promise<boolean> { |     protected async fetchLessonData(): Promise<boolean> { | ||||||
|         try { |         try { | ||||||
|             // Wait for any ongoing sync to finish. We won't sync a lesson while it's being played.
 |             this.lesson = await AddonModLesson.getLesson(this.courseId, this.cmId); | ||||||
|             await AddonModLessonSync.waitForSync(this.lessonId); |  | ||||||
| 
 | 
 | ||||||
|             this.lesson = await AddonModLesson.getLessonById(this.courseId, this.lessonId); |  | ||||||
|             this.title = this.lesson.name; // Temporary title.
 |             this.title = this.lesson.name; // Temporary title.
 | ||||||
| 
 | 
 | ||||||
|  |             // Block the lesson so it cannot be synced.
 | ||||||
|  |             CoreSync.blockOperation(this.component, this.lesson.id); | ||||||
|  | 
 | ||||||
|  |             // Wait for any ongoing sync to finish. We won't sync a lesson while it's being played.
 | ||||||
|  |             await AddonModLessonSync.waitForSync(this.lesson.id); | ||||||
|  | 
 | ||||||
|             // If lesson has offline data already, use offline mode.
 |             // If lesson has offline data already, use offline mode.
 | ||||||
|             this.offline = await AddonModLessonOffline.hasOfflineData(this.lessonId); |             this.offline = await AddonModLessonOffline.hasOfflineData(this.lesson.id); | ||||||
| 
 | 
 | ||||||
|             if (!this.offline && !CoreApp.isOnline() && AddonModLesson.isLessonOffline(this.lesson) && |             if (!this.offline && !CoreApp.isOnline() && AddonModLesson.isLessonOffline(this.lesson) && | ||||||
|                 !this.review) { |                 !this.review) { | ||||||
| @ -275,7 +278,7 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy, CanLeave { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             const options = { |             const options = { | ||||||
|                 cmId: this.lesson.coursemodule, |                 cmId: this.cmId, | ||||||
|                 readingStrategy: this.offline ? CoreSitesReadingStrategy.PreferCache : CoreSitesReadingStrategy.OnlyNetwork, |                 readingStrategy: this.offline ? CoreSitesReadingStrategy.PreferCache : CoreSitesReadingStrategy.OnlyNetwork, | ||||||
|             }; |             }; | ||||||
|             this.accessInfo = await this.callFunction<AddonModLessonGetAccessInformationWSResponse>( |             this.accessInfo = await this.callFunction<AddonModLessonGetAccessInformationWSResponse>( | ||||||
| @ -306,7 +309,7 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy, CanLeave { | |||||||
|                 // Lesson uses password, get the whole lesson object.
 |                 // Lesson uses password, get the whole lesson object.
 | ||||||
|                 const options = { |                 const options = { | ||||||
|                     password: this.password, |                     password: this.password, | ||||||
|                     cmId: this.lesson.coursemodule, |                     cmId: this.cmId, | ||||||
|                     readingStrategy: this.offline ? CoreSitesReadingStrategy.PreferCache : CoreSitesReadingStrategy.OnlyNetwork, |                     readingStrategy: this.offline ? CoreSitesReadingStrategy.PreferCache : CoreSitesReadingStrategy.OnlyNetwork, | ||||||
|                 }; |                 }; | ||||||
|                 promises.push(this.callFunction<AddonModLessonLessonWSData>( |                 promises.push(this.callFunction<AddonModLessonLessonWSData>( | ||||||
| @ -322,7 +325,7 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy, CanLeave { | |||||||
|             if (this.offline) { |             if (this.offline) { | ||||||
|                 // Offline mode, get the list of possible jumps to allow navigation.
 |                 // Offline mode, get the list of possible jumps to allow navigation.
 | ||||||
|                 promises.push(AddonModLesson.getPagesPossibleJumps(this.lesson.id, { |                 promises.push(AddonModLesson.getPagesPossibleJumps(this.lesson.id, { | ||||||
|                     cmId: this.lesson.coursemodule, |                     cmId: this.cmId, | ||||||
|                     readingStrategy: CoreSitesReadingStrategy.PreferCache, |                     readingStrategy: CoreSitesReadingStrategy.PreferCache, | ||||||
|                 }).then((jumpList) => { |                 }).then((jumpList) => { | ||||||
|                     this.jumps = jumpList; |                     this.jumps = jumpList; | ||||||
| @ -344,7 +347,7 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy, CanLeave { | |||||||
| 
 | 
 | ||||||
|             if (this.review && this.retakeToReview && CoreUtils.isWebServiceError(error)) { |             if (this.review && this.retakeToReview && CoreUtils.isWebServiceError(error)) { | ||||||
|                 // The user cannot review the retake. Unmark the retake as being finished in sync.
 |                 // The user cannot review the retake. Unmark the retake as being finished in sync.
 | ||||||
|                 await AddonModLessonSync.deleteRetakeFinishedInSync(this.lessonId); |                 await AddonModLessonSync.deleteRetakeFinishedInSync(this.lesson!.id); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             CoreDomUtils.showErrorModalDefault(error, 'core.course.errorgetmodule', true); |             CoreDomUtils.showErrorModalDefault(error, 'core.course.errorgetmodule', true); | ||||||
| @ -373,7 +376,7 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy, CanLeave { | |||||||
|             if (result?.warnings?.length) { |             if (result?.warnings?.length) { | ||||||
|                 // Some data was deleted. Check if the retake has changed.
 |                 // Some data was deleted. Check if the retake has changed.
 | ||||||
|                 const info = await AddonModLesson.getAccessInformation(this.lesson!.id, { |                 const info = await AddonModLesson.getAccessInformation(this.lesson!.id, { | ||||||
|                     cmId: this.lesson!.coursemodule, |                     cmId: this.cmId, | ||||||
|                 }); |                 }); | ||||||
| 
 | 
 | ||||||
|                 if (info.attemptscount != this.accessInfo!.attemptscount) { |                 if (info.attemptscount != this.accessInfo!.attemptscount) { | ||||||
| @ -485,7 +488,7 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy, CanLeave { | |||||||
|         if (this.lesson!.timelimit && !this.accessInfo!.canmanage) { |         if (this.lesson!.timelimit && !this.accessInfo!.canmanage) { | ||||||
|             // Get the last lesson timer.
 |             // Get the last lesson timer.
 | ||||||
|             const timers = await AddonModLesson.getTimers(this.lesson!.id, { |             const timers = await AddonModLesson.getTimers(this.lesson!.id, { | ||||||
|                 cmId: this.lesson!.coursemodule, |                 cmId: this.cmId, | ||||||
|                 readingStrategy: CoreSitesReadingStrategy.OnlyNetwork, |                 readingStrategy: CoreSitesReadingStrategy.OnlyNetwork, | ||||||
|             }); |             }); | ||||||
| 
 | 
 | ||||||
| @ -510,12 +513,12 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy, CanLeave { | |||||||
|             this.loadingMenu = true; |             this.loadingMenu = true; | ||||||
|             const options = { |             const options = { | ||||||
|                 password: this.password, |                 password: this.password, | ||||||
|                 cmId: this.lesson!.coursemodule, |                 cmId: this.cmId, | ||||||
|                 readingStrategy: this.offline ? CoreSitesReadingStrategy.PreferCache : CoreSitesReadingStrategy.OnlyNetwork, |                 readingStrategy: this.offline ? CoreSitesReadingStrategy.PreferCache : CoreSitesReadingStrategy.OnlyNetwork, | ||||||
|             }; |             }; | ||||||
| 
 | 
 | ||||||
|             const pages = await this.callFunction<AddonModLessonGetPagesPageWSData[]>( |             const pages = await this.callFunction<AddonModLessonGetPagesPageWSData[]>( | ||||||
|                 AddonModLesson.getPages.bind(AddonModLesson.instance, this.lessonId, options), |                 AddonModLesson.getPages.bind(AddonModLesson.instance, this.lesson!.id, options), | ||||||
|                 options, |                 options, | ||||||
|             ); |             ); | ||||||
| 
 | 
 | ||||||
| @ -543,7 +546,7 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy, CanLeave { | |||||||
|             password: this.password, |             password: this.password, | ||||||
|             review: this.review, |             review: this.review, | ||||||
|             includeContents: true, |             includeContents: true, | ||||||
|             cmId: this.lesson!.coursemodule, |             cmId: this.cmId, | ||||||
|             readingStrategy: this.offline ? CoreSitesReadingStrategy.PreferCache : CoreSitesReadingStrategy.OnlyNetwork, |             readingStrategy: this.offline ? CoreSitesReadingStrategy.PreferCache : CoreSitesReadingStrategy.OnlyNetwork, | ||||||
|             accessInfo: this.accessInfo, |             accessInfo: this.accessInfo, | ||||||
|             jumps: this.jumps, |             jumps: this.jumps, | ||||||
| @ -638,15 +641,15 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy, CanLeave { | |||||||
|                 // Lesson allows offline and the user changed some data in server. Update cached data.
 |                 // Lesson allows offline and the user changed some data in server. Update cached data.
 | ||||||
|                 const retake = this.accessInfo!.attemptscount; |                 const retake = this.accessInfo!.attemptscount; | ||||||
|                 const options = { |                 const options = { | ||||||
|                     cmId: this.lesson!.coursemodule, |                     cmId: this.cmId, | ||||||
|                     readingStrategy: CoreSitesReadingStrategy.OnlyNetwork, |                     readingStrategy: CoreSitesReadingStrategy.OnlyNetwork, | ||||||
|                 }; |                 }; | ||||||
| 
 | 
 | ||||||
|                 // Update in background the list of content pages viewed or question attempts.
 |                 // Update in background the list of content pages viewed or question attempts.
 | ||||||
|                 if (AddonModLesson.isQuestionPage(this.pageData?.page?.type || -1)) { |                 if (AddonModLesson.isQuestionPage(this.pageData?.page?.type || -1)) { | ||||||
|                     AddonModLesson.getQuestionsAttemptsOnline(this.lessonId, retake, options); |                     AddonModLesson.getQuestionsAttemptsOnline(this.lesson!.id, retake, options); | ||||||
|                 } else { |                 } else { | ||||||
|                     AddonModLesson.getContentPagesViewedOnline(this.lessonId, retake, options); |                     AddonModLesson.getContentPagesViewedOnline(this.lesson!.id, retake, options); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -55,7 +55,7 @@ export class AddonModLessonUserRetakePage implements OnInit { | |||||||
|     loaded?: boolean; // Whether the data has been loaded.
 |     loaded?: boolean; // Whether the data has been loaded.
 | ||||||
|     timeTakenReadable?: string; // Time taken in a readable format.
 |     timeTakenReadable?: string; // Time taken in a readable format.
 | ||||||
| 
 | 
 | ||||||
|     protected lessonId!: number; // The lesson ID the retake belongs to.
 |     protected cmId!: number; // The lesson ID the retake belongs to.
 | ||||||
|     protected userId?: number; // User ID to see the retakes.
 |     protected userId?: number; // User ID to see the retakes.
 | ||||||
|     protected retakeNumber?: number; // Number of the initial retake to see.
 |     protected retakeNumber?: number; // Number of the initial retake to see.
 | ||||||
|     protected previousSelectedRetake?: number; // To be able to detect the previous selected retake when it has changed.
 |     protected previousSelectedRetake?: number; // To be able to detect the previous selected retake when it has changed.
 | ||||||
| @ -64,7 +64,7 @@ export class AddonModLessonUserRetakePage implements OnInit { | |||||||
|      * Component being initialized. |      * Component being initialized. | ||||||
|      */ |      */ | ||||||
|     ngOnInit(): void { |     ngOnInit(): void { | ||||||
|         this.lessonId = CoreNavigator.getRouteNumberParam('lessonId')!; |         this.cmId = CoreNavigator.getRouteNumberParam('cmId')!; | ||||||
|         this.courseId = CoreNavigator.getRouteNumberParam('courseId')!; |         this.courseId = CoreNavigator.getRouteNumberParam('courseId')!; | ||||||
|         this.userId = CoreNavigator.getRouteNumberParam('userId') || CoreSites.getCurrentSiteUserId(); |         this.userId = CoreNavigator.getRouteNumberParam('userId') || CoreSites.getCurrentSiteUserId(); | ||||||
|         this.retakeNumber = CoreNavigator.getRouteNumberParam('retake'); |         this.retakeNumber = CoreNavigator.getRouteNumberParam('retake'); | ||||||
| @ -111,11 +111,11 @@ export class AddonModLessonUserRetakePage implements OnInit { | |||||||
|      */ |      */ | ||||||
|     protected async fetchData(): Promise<void> { |     protected async fetchData(): Promise<void> { | ||||||
|         try { |         try { | ||||||
|             this.lesson = await AddonModLesson.getLessonById(this.courseId, this.lessonId); |             this.lesson = await AddonModLesson.getLesson(this.courseId, this.cmId); | ||||||
| 
 | 
 | ||||||
|             // Get the retakes overview for all participants.
 |             // Get the retakes overview for all participants.
 | ||||||
|             const data = await AddonModLesson.getRetakesOverview(this.lesson.id, { |             const data = await AddonModLesson.getRetakesOverview(this.lesson.id, { | ||||||
|                 cmId: this.lesson.coursemodule, |                 cmId: this.cmId, | ||||||
|             }); |             }); | ||||||
| 
 | 
 | ||||||
|             // Search the student.
 |             // Search the student.
 | ||||||
| @ -185,8 +185,8 @@ export class AddonModLessonUserRetakePage implements OnInit { | |||||||
|     protected async setRetake(retakeNumber: number): Promise<void> { |     protected async setRetake(retakeNumber: number): Promise<void> { | ||||||
|         this.selectedRetake = retakeNumber; |         this.selectedRetake = retakeNumber; | ||||||
| 
 | 
 | ||||||
|         const retakeData = await AddonModLesson.getUserRetake(this.lessonId, retakeNumber, { |         const retakeData = await AddonModLesson.getUserRetake(this.lesson!.id, retakeNumber, { | ||||||
|             cmId: this.lesson!.coursemodule, |             cmId: this.cmId, | ||||||
|             userId: this.userId, |             userId: this.userId, | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -65,7 +65,7 @@ export class AddonModLessonGradeLinkHandlerService extends CoreContentLinksModul | |||||||
|             if (accessInfo.canviewreports) { |             if (accessInfo.canviewreports) { | ||||||
|                 // User can view reports, go to view the report.
 |                 // User can view reports, go to view the report.
 | ||||||
|                 CoreNavigator.navigateToSitePath( |                 CoreNavigator.navigateToSitePath( | ||||||
|                     AddonModLessonModuleHandlerService.PAGE_NAME + `/user-retake/${courseId}/${module.instance}`, |                     AddonModLessonModuleHandlerService.PAGE_NAME + `/${courseId}/${module.id}/user-retake`, | ||||||
|                     { |                     { | ||||||
|                         params: { userId: Number(params.userid) }, |                         params: { userId: Number(params.userid) }, | ||||||
|                         siteId, |                         siteId, | ||||||
|  | |||||||
| @ -122,11 +122,9 @@ export class AddonModLessonReportLinkHandlerService extends CoreContentLinksHand | |||||||
|      * |      * | ||||||
|      * @param moduleId Module ID. |      * @param moduleId Module ID. | ||||||
|      * @param userId User ID. |      * @param userId User ID. | ||||||
|      * @param courseId Course ID. |  | ||||||
|      * @param retake Retake to open. |      * @param retake Retake to open. | ||||||
|      * @param groupId Group ID. |  | ||||||
|      * @param siteId Site ID. |      * @param siteId Site ID. | ||||||
|      * @param navCtrl The NavController to use to navigate. |      * @param courseId Course ID. | ||||||
|      * @return Promise resolved when done. |      * @return Promise resolved when done. | ||||||
|      */ |      */ | ||||||
|     protected async openUserRetake( |     protected async openUserRetake( | ||||||
| @ -150,7 +148,7 @@ export class AddonModLessonReportLinkHandlerService extends CoreContentLinksHand | |||||||
|             }; |             }; | ||||||
| 
 | 
 | ||||||
|             CoreNavigator.navigateToSitePath( |             CoreNavigator.navigateToSitePath( | ||||||
|                 AddonModLessonModuleHandlerService.PAGE_NAME + `/user-retake/${courseId}/${module.instance}`, |                 AddonModLessonModuleHandlerService.PAGE_NAME + `/${courseId}/${module.id}/user-retake`, | ||||||
|                 { params, siteId }, |                 { params, siteId }, | ||||||
|             ); |             ); | ||||||
|         } catch (error) { |         } catch (error) { | ||||||
|  | |||||||
| @ -1486,7 +1486,7 @@ export class AddonModLessonProvider { | |||||||
| 
 | 
 | ||||||
|         const response = await site.read<AddonModLessonGetLessonWSResponse>('mod_lesson_get_lesson', params, preSets); |         const response = await site.read<AddonModLessonGetLessonWSResponse>('mod_lesson_get_lesson', params, preSets); | ||||||
| 
 | 
 | ||||||
|         if (typeof response.lesson.ongoing != 'undefined') { |         if (typeof response.lesson.ongoing == 'undefined') { | ||||||
|             // Basic data not received, password is wrong. Remove stored password.
 |             // Basic data not received, password is wrong. Remove stored password.
 | ||||||
|             this.removeStoredPassword(lessonId, site.id); |             this.removeStoredPassword(lessonId, site.id); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -14,7 +14,7 @@ | |||||||
| 
 | 
 | ||||||
|         <!-- Form to edit the file's name. --> |         <!-- Form to edit the file's name. --> | ||||||
|         <ion-input type="text" name="filename" [placeholder]="'core.filename' | translate" autocapitalize="none" autocorrect="off" |         <ion-input type="text" name="filename" [placeholder]="'core.filename' | translate" autocapitalize="none" autocorrect="off" | ||||||
|             (click)="$event.stopPropagation()" [core-auto-focus] [(ngModel)]="newFileName" *ngIf="editMode"> |             (click)="$event.stopPropagation()" [autofocus]="true" [(ngModel)]="newFileName" *ngIf="editMode"> | ||||||
|         </ion-input> |         </ion-input> | ||||||
| 
 | 
 | ||||||
|         <div class="buttons" slot="end" *ngIf="manage"> |         <div class="buttons" slot="end" *ngIf="manage"> | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| <form #messageForm> | <form #messageForm> | ||||||
|     <textarea class="core-send-message-input" [core-auto-focus]="showKeyboard" [placeholder]="placeholder" rows="1" core-auto-rows |     <textarea class="core-send-message-input" [autofocus]="showKeyboard" [placeholder]="placeholder" rows="1" core-auto-rows | ||||||
|         [(ngModel)]="message" name="message" (onResize)="textareaResized()" (keydown.enter)="enterClicked($event)" |         [(ngModel)]="message" name="message" (onResize)="textareaResized()" (keydown.enter)="enterClicked($event)" | ||||||
|         (keydown.control.enter)="enterClicked($event, 'control')" (keydown.meta.enter)="enterClicked($event, 'meta')" |         (keydown.control.enter)="enterClicked($event, 'control')" (keydown.meta.enter)="enterClicked($event, 'meta')" | ||||||
|         aria-multiline="true"></textarea> |         aria-multiline="true"></textarea> | ||||||
| @ -10,4 +10,3 @@ | |||||||
|         </ion-button> |         </ion-button> | ||||||
|     </ion-buttons> |     </ion-buttons> | ||||||
| </form> | </form> | ||||||
| 
 |  | ||||||
|  | |||||||
| @ -21,6 +21,8 @@ import { CoreUtils } from '@services/utils/utils'; | |||||||
|  * Directive to auto focus an element when a view is loaded. |  * Directive to auto focus an element when a view is loaded. | ||||||
|  * |  * | ||||||
|  * You can apply it conditionallity assigning it a boolean value: <ion-input [core-auto-focus]="{{showKeyboard}}"> |  * You can apply it conditionallity assigning it a boolean value: <ion-input [core-auto-focus]="{{showKeyboard}}"> | ||||||
|  |  * | ||||||
|  |  * @deprecated since 3.9.5. ion-input now supports an [autofocus] attribute, please use that one instead. | ||||||
|  */ |  */ | ||||||
| @Directive({ | @Directive({ | ||||||
|     selector: '[core-auto-focus]', |     selector: '[core-auto-focus]', | ||||||
| @ -39,16 +41,7 @@ export class CoreAutoFocusDirective implements OnInit { | |||||||
|      * Component being initialized. |      * Component being initialized. | ||||||
|      */ |      */ | ||||||
|     ngOnInit(): void { |     ngOnInit(): void { | ||||||
|         // @todo
 |  | ||||||
|         // if (this.navCtrl.isTransitioning()) {
 |  | ||||||
|         //     // Navigating to a new page. Wait for the transition to be over.
 |  | ||||||
|         //     const subscription = this.navCtrl.viewDidEnter.subscribe(() => {
 |  | ||||||
|         //         this.autoFocus();
 |  | ||||||
|         //         subscription.unsubscribe();
 |  | ||||||
|         //     });
 |  | ||||||
|         // } else {
 |  | ||||||
|         this.autoFocus(); |         this.autoFocus(); | ||||||
|         // }
 |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | |||||||
| @ -21,8 +21,9 @@ | |||||||
|                     [class.core-section-download]="downloadEnabled"> |                     [class.core-section-download]="downloadEnabled"> | ||||||
|                     <ion-button class="core-button-select button-no-uppercase" (click)="showSectionSelector()" |                     <ion-button class="core-button-select button-no-uppercase" (click)="showSectionSelector()" | ||||||
|                         aria-haspopup="true" [attr.aria-expanded]="sectionSelectorExpanded" |                         aria-haspopup="true" [attr.aria-expanded]="sectionSelectorExpanded" | ||||||
|                         id="core-course-section-button" expand="block"> <!-- @todo: attr.aria-label? --> |                         id="core-course-section-button" expand="block"> | ||||||
|                         <ion-icon name="fas-folder" slot="start"></ion-icon> |                         <ion-icon name="fas-folder" slot="start" aria-hidden="true"></ion-icon> | ||||||
|  |                         <span class="sr-only" *ngIf="selectedSection">{{ 'core.course.sections' | translate }}:</span> | ||||||
|                         <span class="core-button-select-text"> |                         <span class="core-button-select-text"> | ||||||
|                             <core-format-text *ngIf="selectedSection" [text]="selectedSection.name" contextLevel="course" |                             <core-format-text *ngIf="selectedSection" [text]="selectedSection.name" contextLevel="course" | ||||||
|                                 [contextInstanceId]="course?.id" [clean]="true" [singleLine]="true"> |                                 [contextInstanceId]="course?.id" [clean]="true" [singleLine]="true"> | ||||||
|  | |||||||
| @ -9,23 +9,25 @@ | |||||||
|     </ion-toolbar> |     </ion-toolbar> | ||||||
| </ion-header> | </ion-header> | ||||||
| <ion-content> | <ion-content> | ||||||
|     <ion-list id="core-course-section-selector" role="menu"> |     <ion-list id="core-course-section-selector"> | ||||||
|         <ng-container *ngFor="let section of sections"> |         <ng-container *ngFor="let section of sections"> | ||||||
|             <ion-item *ngIf="!section.hiddenbynumsections && section.id != stealthModulesSectionId" class="ion-text-wrap" |             <ion-item *ngIf="!section.hiddenbynumsections && section.id != stealthModulesSectionId" class="ion-text-wrap" | ||||||
|                 (click)="selectSection(section)" [class.core-selected-item]="selected?.id == section.id" |                 (click)="selectSection(section)" [class.core-selected-item]="selected?.id == section.id" | ||||||
|                 [class.item-dimmed]="section.visible === 0 || section.uservisible === false" detail="false" role="menuitem" |                 [class.item-dimmed]="section.visible === 0 || section.uservisible === false" detail="false" | ||||||
|                 [attr.aria-hidden]="section.uservisible === false" button> |                 [attr.aria-hidden]="section.uservisible === false" button> | ||||||
| 
 | 
 | ||||||
|                 <ion-icon name="fas-folder" slot="start"></ion-icon> |                 <ion-icon name="fas-folder" slot="start" aria-hidden="true"></ion-icon> | ||||||
|                 <ion-label> |                 <ion-label> | ||||||
|                     <h2><core-format-text [text]="section.name" contextLevel="course" [contextInstanceId]="course?.id"> |                     <h2><core-format-text [text]="section.name" contextLevel="course" [contextInstanceId]="course?.id"> | ||||||
|                     </core-format-text></h2> |                     </core-format-text></h2> | ||||||
|                     <core-progress-bar *ngIf="section.progress >= 0" [progress]="section.progress"></core-progress-bar> |                     <core-progress-bar *ngIf="section.progress >= 0" [progress]="section.progress"></core-progress-bar> | ||||||
| 
 | 
 | ||||||
|                     <ion-badge color="secondary" *ngIf="section.visible === 0 && section.uservisible !== false" class="ion-text-wrap"> |                     <ion-badge color="secondary" *ngIf="section.visible === 0 && section.uservisible !== false" | ||||||
|  |                         class="ion-text-wrap"> | ||||||
|                         {{ 'core.course.hiddenfromstudents' | translate }} |                         {{ 'core.course.hiddenfromstudents' | translate }} | ||||||
|                     </ion-badge> |                     </ion-badge> | ||||||
|                     <ion-badge color="secondary" *ngIf="section.visible === 0 && section.uservisible === false" class="ion-text-wrap"> |                     <ion-badge color="secondary" *ngIf="section.visible === 0 && section.uservisible === false" | ||||||
|  |                         class="ion-text-wrap"> | ||||||
|                         {{ 'core.notavailable' | translate }} |                         {{ 'core.notavailable' | translate }} | ||||||
|                     </ion-badge> |                     </ion-badge> | ||||||
|                     <ion-badge color="secondary" *ngIf="section.availabilityinfo" class="ion-text-wrap"> |                     <ion-badge color="secondary" *ngIf="section.availabilityinfo" class="ion-text-wrap"> | ||||||
|  | |||||||
| @ -11,7 +11,7 @@ | |||||||
|             [class.core-course-with-buttons]="courseOptionMenuEnabled || (downloadCourseEnabled && showDownload)" |             [class.core-course-with-buttons]="courseOptionMenuEnabled || (downloadCourseEnabled && showDownload)" | ||||||
|             [class.core-course-with-spinner]="(downloadCourseEnabled && prefetchCourseData.icon == 'spinner') || showSpinner"> |             [class.core-course-with-spinner]="(downloadCourseEnabled && prefetchCourseData.icon == 'spinner') || showSpinner"> | ||||||
|             <p *ngIf="course.categoryname || (course.displayname && course.shortname && course.fullname != course.displayname)" |             <p *ngIf="course.categoryname || (course.displayname && course.shortname && course.fullname != course.displayname)" | ||||||
|                 class="core-course-additional-info"> |                 class="core-course-additional-info" aria-hidden="true"> | ||||||
|                 <span *ngIf="course.categoryname" class="core-course-category"> |                 <span *ngIf="course.categoryname" class="core-course-category"> | ||||||
|                     <core-format-text [text]="course.categoryname"></core-format-text> |                     <core-format-text [text]="course.categoryname"></core-format-text> | ||||||
|                 </span> |                 </span> | ||||||
| @ -24,7 +24,10 @@ | |||||||
|                 </span> |                 </span> | ||||||
|             </p> |             </p> | ||||||
|             <h2> |             <h2> | ||||||
|                 <ion-icon name="fas-star" *ngIf="course.isfavourite"></ion-icon> |                 <ion-icon name="fas-star" *ngIf="course.isfavourite" [attr.aria-label]="'core.courses.favourite' | translate"> | ||||||
|  |                 </ion-icon> | ||||||
|  |                 <span class="sr-only" *ngIf="course.isfavourite">{{ 'core.courses.aria:favourite' | translate }}</span> | ||||||
|  |                 <span class="sr-only">{{ 'core.courses.aria:coursename' | translate }}</span> | ||||||
|                 <core-format-text [text]="course.fullname" contextLevel="course" [contextInstanceId]="course.id"></core-format-text> |                 <core-format-text [text]="course.fullname" contextLevel="course" [contextInstanceId]="course.id"></core-format-text> | ||||||
|             </h2> |             </h2> | ||||||
|         </ion-label> |         </ion-label> | ||||||
| @ -50,9 +53,10 @@ | |||||||
|             </ion-button> |             </ion-button> | ||||||
|         </div> |         </div> | ||||||
|     </ion-item> |     </ion-item> | ||||||
|     <ion-item *ngIf="showAll && course.progress! >= 0 && course.completionusertracked !== false" |     <ion-item *ngIf="showAll && course.progress! >= 0 && course.completionusertracked !== false" lines="none"> | ||||||
|         lines="none"> |         <ion-label> | ||||||
|         <ion-label><core-progress-bar [progress]="course.progress"></core-progress-bar></ion-label> |             <core-progress-bar [progress]="course.progress"></core-progress-bar> | ||||||
|  |         </ion-label> | ||||||
|     </ion-item> |     </ion-item> | ||||||
|     <ng-content></ng-content> |     <ng-content></ng-content> | ||||||
| </ion-card> | </ion-card> | ||||||
|  | |||||||
| @ -20,7 +20,7 @@ | |||||||
|                     type="password" |                     type="password" | ||||||
|                     placeholder="{{ 'core.courses.password' | translate }}" |                     placeholder="{{ 'core.courses.password' | translate }}" | ||||||
|                     [(ngModel)]="password" |                     [(ngModel)]="password" | ||||||
|                     [core-auto-focus] |                     [autofocus]="true" | ||||||
|                     [clearOnEdit]="false"> |                     [clearOnEdit]="false"> | ||||||
|                 </ion-input> |                 </ion-input> | ||||||
|             </core-show-password> |             </core-show-password> | ||||||
|  | |||||||
| @ -1,6 +1,9 @@ | |||||||
| { | { | ||||||
|     "addtofavourites": "Star this course", |     "addtofavourites": "Star this course", | ||||||
|     "allowguests": "This course allows guest users to enter", |     "allowguests": "This course allows guest users to enter", | ||||||
|  |     "aria:coursename": "Course name", | ||||||
|  |     "aria:courseprogress": "Course progress:", | ||||||
|  |     "aria:favourite": "Course is starred", | ||||||
|     "availablecourses": "Available courses", |     "availablecourses": "Available courses", | ||||||
|     "cannotretrievemorecategories": "Categories deeper than level {{$a}} cannot be retrieved.", |     "cannotretrievemorecategories": "Categories deeper than level {{$a}} cannot be retrieved.", | ||||||
|     "categories": "Course categories", |     "categories": "Course categories", | ||||||
| @ -13,6 +16,7 @@ | |||||||
|     "errorloadplugins": "The plugins required by this course could not be loaded correctly. Please reload the app to try again.", |     "errorloadplugins": "The plugins required by this course could not be loaded correctly. Please reload the app to try again.", | ||||||
|     "errorsearching": "An error occurred while searching.", |     "errorsearching": "An error occurred while searching.", | ||||||
|     "errorselfenrol": "An error occurred while self enrolling.", |     "errorselfenrol": "An error occurred while self enrolling.", | ||||||
|  |     "favourite": "Starred course", | ||||||
|     "filtermycourses": "Filter my courses", |     "filtermycourses": "Filter my courses", | ||||||
|     "frontpage": "Front page", |     "frontpage": "Front page", | ||||||
|     "hidecourse": "Remove from view", |     "hidecourse": "Remove from view", | ||||||
|  | |||||||
| @ -31,7 +31,7 @@ | |||||||
|             <ion-item> |             <ion-item> | ||||||
|                 <ion-label></ion-label> |                 <ion-label></ion-label> | ||||||
|                 <ion-input type="text" name="value" placeholder="{{ 'core.login.usernameoremail' | translate }}" |                 <ion-input type="text" name="value" placeholder="{{ 'core.login.usernameoremail' | translate }}" | ||||||
|                     formControlName="value" autocapitalize="none" autocorrect="off" [core-auto-focus]="autoFocus"> |                     formControlName="value" autocapitalize="none" autocorrect="off" [autofocus]="autoFocus"> | ||||||
|                 </ion-input> |                 </ion-input> | ||||||
|             </ion-item> |             </ion-item> | ||||||
|             <ion-button type="submit" class="ion-margin" expand="block" [disabled]="!myForm.valid"> |             <ion-button type="submit" class="ion-margin" expand="block" [disabled]="!myForm.valid"> | ||||||
|  | |||||||
| @ -27,7 +27,7 @@ | |||||||
|                     <h2>{{ 'core.login.siteaddress' | translate }}</h2> |                     <h2>{{ 'core.login.siteaddress' | translate }}</h2> | ||||||
|                 </ion-label> |                 </ion-label> | ||||||
|                 <ion-input name="url" type="url" placeholder="{{ 'core.login.siteaddressplaceholder' | translate }}" |                 <ion-input name="url" type="url" placeholder="{{ 'core.login.siteaddressplaceholder' | translate }}" | ||||||
|                     formControlName="siteUrl" [core-auto-focus]="showKeyboard && !showScanQR"> |                     formControlName="siteUrl" [autofocus]="showKeyboard && !showScanQR"> | ||||||
|                 </ion-input> |                 </ion-input> | ||||||
|             </ion-item> |             </ion-item> | ||||||
|         </ng-container> |         </ng-container> | ||||||
| @ -37,7 +37,7 @@ | |||||||
|                     <h2>{{ 'core.login.siteaddress' | translate }}</h2> |                     <h2>{{ 'core.login.siteaddress' | translate }}</h2> | ||||||
|                 </ion-label> |                 </ion-label> | ||||||
|                 <ion-input name="url" placeholder="{{ 'core.login.siteaddressplaceholder' | translate }}" formControlName="siteUrl" |                 <ion-input name="url" placeholder="{{ 'core.login.siteaddressplaceholder' | translate }}" formControlName="siteUrl" | ||||||
|                     [core-auto-focus]="showKeyboard && !showScanQR" (ionChange)="searchSite($event, siteForm.value.siteUrl)"> |                     [autofocus]="showKeyboard && !showScanQR" (ionChange)="searchSite($event, siteForm.value.siteUrl)"> | ||||||
|                 </ion-input> |                 </ion-input> | ||||||
|             </ion-item> |             </ion-item> | ||||||
| 
 | 
 | ||||||
| @ -49,7 +49,7 @@ | |||||||
|                 </ion-item> |                 </ion-item> | ||||||
|                 <ion-item button *ngIf="enteredSiteUrl" (click)="connect($event, enteredSiteUrl.url)" |                 <ion-item button *ngIf="enteredSiteUrl" (click)="connect($event, enteredSiteUrl.url)" | ||||||
|                     [attr.aria-label]="'core.login.connect' | translate" detail-push class="core-login-entered-site"> |                     [attr.aria-label]="'core.login.connect' | translate" detail-push class="core-login-entered-site"> | ||||||
|                     <ion-thumbnail slot="start"> |                     <ion-thumbnail slot="start" aria-hidden="true"> | ||||||
|                         <ion-icon name="fas-pen"></ion-icon> |                         <ion-icon name="fas-pen"></ion-icon> | ||||||
|                     </ion-thumbnail> |                     </ion-thumbnail> | ||||||
|                     <ion-label> |                     <ion-label> | ||||||
| @ -101,7 +101,8 @@ | |||||||
| 
 | 
 | ||||||
|     <ng-container *ngIf="showScanQR && !hasSites && !enteredSiteUrl"> |     <ng-container *ngIf="showScanQR && !hasSites && !enteredSiteUrl"> | ||||||
|         <div class="ion-text-center ion-padding ion-margin-top">{{ 'core.login.or' | translate }}</div> |         <div class="ion-text-center ion-padding ion-margin-top">{{ 'core.login.or' | translate }}</div> | ||||||
|         <ion-button expand="block" color="light" class="ion-margin" lines="none" (click)="showInstructionsAndScanQR()"> |         <ion-button expand="block" color="light" class="ion-margin" lines="none" (click)="showInstructionsAndScanQR()" | ||||||
|  |             aria-haspopup="true"> | ||||||
|             <ion-icon slot="start" name="fas-qrcode" aria-hidden="true"></ion-icon> |             <ion-icon slot="start" name="fas-qrcode" aria-hidden="true"></ion-icon> | ||||||
|             <ion-label>{{ 'core.scanqr' | translate }}</ion-label> |             <ion-label>{{ 'core.scanqr' | translate }}</ion-label> | ||||||
|         </ion-button> |         </ion-button> | ||||||
| @ -109,7 +110,8 @@ | |||||||
| 
 | 
 | ||||||
|     <!-- Help. --> |     <!-- Help. --> | ||||||
|     <ion-list lines="none" class="ion-margin-top"> |     <ion-list lines="none" class="ion-margin-top"> | ||||||
|         <ion-item button class="ion-text-center ion-text-wrap core-login-need-help" (click)="showHelp()" detail="false"> |         <ion-item button class="ion-text-center ion-text-wrap core-login-need-help" (click)="showHelp()" detail="false" | ||||||
|  |             aria-haspopup="true"> | ||||||
|             <ion-label>{{ 'core.needhelp' | translate }}</ion-label> |             <ion-label>{{ 'core.needhelp' | translate }}</ion-label> | ||||||
|         </ion-item> |         </ion-item> | ||||||
|     </ion-list> |     </ion-list> | ||||||
|  | |||||||
| @ -13,7 +13,6 @@ | |||||||
|     </ion-toolbar> |     </ion-toolbar> | ||||||
| </ion-header> | </ion-header> | ||||||
| <ion-content> | <ion-content> | ||||||
|     <!-- @todo --> |  | ||||||
|     <core-loading [hideUntil]="loaded"> |     <core-loading [hideUntil]="loaded"> | ||||||
|         <core-tabs-outlet *ngIf="tabs.length > 0" [selectedIndex]="selectedTab" [hideUntil]="loaded" [tabs]="tabs"> |         <core-tabs-outlet *ngIf="tabs.length > 0" [selectedIndex]="selectedTab" [hideUntil]="loaded" [tabs]="tabs"> | ||||||
|         </core-tabs-outlet> |         </core-tabs-outlet> | ||||||
|  | |||||||
| @ -14,7 +14,6 @@ | |||||||
| 
 | 
 | ||||||
| import { Injectable } from '@angular/core'; | import { Injectable } from '@angular/core'; | ||||||
| import { makeSingleton } from '@singletons'; | import { makeSingleton } from '@singletons'; | ||||||
| import { CoreMainMenuHomeDelegate } from '../home-delegate'; |  | ||||||
| import { CoreMainMenuHandler, CoreMainMenuHandlerData } from '../mainmenu-delegate'; | import { CoreMainMenuHandler, CoreMainMenuHandlerData } from '../mainmenu-delegate'; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
| @ -29,27 +28,14 @@ export class CoreMainMenuHomeHandlerService implements CoreMainMenuHandler { | |||||||
|     priority = 1100; |     priority = 1100; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Check if the handler is enabled on a site level. |      * @inheritdoc | ||||||
|      * |  | ||||||
|      * @return Whether or not the handler is enabled on a site level. |  | ||||||
|      */ |      */ | ||||||
|     isEnabled(): Promise<boolean> { |     async isEnabled(): Promise<boolean> { | ||||||
|         return this.isEnabledForSite(); |         return true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Check if the handler is enabled on a certain site. |      * @inheritdoc | ||||||
|      * |  | ||||||
|      * @return Whether or not the handler is enabled on a site level. |  | ||||||
|      */ |  | ||||||
|     async isEnabledForSite(): Promise<boolean> { |  | ||||||
|         return CoreMainMenuHomeDelegate.getHandlers().length > 0; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Returns the data needed to render the handler. |  | ||||||
|      * |  | ||||||
|      * @return Data needed to render the handler. |  | ||||||
|      */ |      */ | ||||||
|     getDisplayData(): CoreMainMenuHandlerData { |     getDisplayData(): CoreMainMenuHandlerData { | ||||||
|         return { |         return { | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ | |||||||
|         <ion-item> |         <ion-item> | ||||||
|             <ion-label></ion-label> |             <ion-label></ion-label> | ||||||
|             <ion-input type="search" name="search" [(ngModel)]="searchText" [placeholder]="placeholder" |             <ion-input type="search" name="search" [(ngModel)]="searchText" [placeholder]="placeholder" | ||||||
|                 [autocorrect]="autocorrect" [spellcheck]="spellcheck" [core-auto-focus]="autoFocus" |                 [autocorrect]="autocorrect" [spellcheck]="spellcheck" [autofocus]="autoFocus" | ||||||
|                 [disabled]="disabled" role="searchbox" (ionFocus)="focus($event)"> |                 [disabled]="disabled" role="searchbox" (ionFocus)="focus($event)"> | ||||||
|             </ion-input> |             </ion-input> | ||||||
|             <ion-button slot="end" fill="clear" type="submit" size="small" [attr.aria-label]="searchLabel" |             <ion-button slot="end" fill="clear" type="submit" size="small" [attr.aria-label]="searchLabel" | ||||||
|  | |||||||
| @ -655,7 +655,7 @@ export class CoreSitesProvider { | |||||||
|      * @return Release number or empty. |      * @return Release number or empty. | ||||||
|      */ |      */ | ||||||
|     getReleaseNumber(rawRelease: string): string { |     getReleaseNumber(rawRelease: string): string { | ||||||
|         const matches = rawRelease.match(/^\d(\.\d(\.\d+)?)?/); |         const matches = rawRelease.match(/^\d+(\.\d+(\.\d+)?)?/); | ||||||
|         if (matches) { |         if (matches) { | ||||||
|             return matches[0]; |             return matches[0]; | ||||||
|         } |         } | ||||||
|  | |||||||
							
								
								
									
										21
									
								
								src/theme/bootstrap.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/theme/bootstrap.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | |||||||
|  | // Text for accessibility, hidden from the view. | ||||||
|  | .sr-only, .accesshide { | ||||||
|  |     position: absolute; | ||||||
|  |     width: 1px; | ||||||
|  |     height: 1px; | ||||||
|  |     padding: 0; | ||||||
|  |     margin: -1px; | ||||||
|  |     overflow: hidden; | ||||||
|  |     clip: rect(0, 0, 0, 0); | ||||||
|  |     white-space: nowrap; | ||||||
|  |     border: 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .sr-only-focusable:active, .sr-only-focusable:focus { | ||||||
|  |     position: static; | ||||||
|  |     width: auto; | ||||||
|  |     height: auto; | ||||||
|  |     overflow: visible; | ||||||
|  |     clip: auto; | ||||||
|  |     white-space: normal; | ||||||
|  | } | ||||||
| @ -436,14 +436,6 @@ ion-button.core-button-select { | |||||||
|     background-color: var(--text-hightlight-background-color); |     background-color: var(--text-hightlight-background-color); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Text for accessibility, hidden from the view. |  | ||||||
| .accesshide { |  | ||||||
|     position: absolute; |  | ||||||
|     left: -10000px; |  | ||||||
|     font-weight: normal; |  | ||||||
|     font-size: 1em; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Monospaced font. | // Monospaced font. | ||||||
| .core-monospaced { | .core-monospaced { | ||||||
|     font-family: Andale Mono,Monaco,Courier New,DejaVu Sans Mono,monospace; |     font-family: Andale Mono,Monaco,Courier New,DejaVu Sans Mono,monospace; | ||||||
|  | |||||||
| @ -23,6 +23,9 @@ | |||||||
| @import "./components/rubrics.scss"; | @import "./components/rubrics.scss"; | ||||||
| @import "./components/mod-label.scss"; | @import "./components/mod-label.scss"; | ||||||
| 
 | 
 | ||||||
|  | /* Some styles from 3rd party libraries. */ | ||||||
|  | @import "./bootstrap.scss"; | ||||||
|  | 
 | ||||||
| /* Core CSS required for Ionic components to work properly */ | /* Core CSS required for Ionic components to work properly */ | ||||||
| @import "~@ionic/angular/css/core.css"; | @import "~@ionic/angular/css/core.css"; | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user