forked from EVOgeek/Vmeda.Online
		
	MOBILE-3998 imscp: Add entry page to IMSCP
This commit is contained in:
		
							parent
							
								
									e37c75ff54
								
							
						
					
					
						commit
						223fd19f1d
					
				| @ -92,7 +92,7 @@ export class AddonModBookIndexComponent extends CoreCourseModuleMainResourceComp | ||||
|     /** | ||||
|      * Open the book in a certain chapter. | ||||
|      * | ||||
|      * @param chapterId Chapter to open, undefined for first chapter. | ||||
|      * @param chapterId Chapter to open, undefined for last chapter viewed. | ||||
|      */ | ||||
|     openBook(chapterId?: number): void { | ||||
|         CoreNavigator.navigate('contents', { | ||||
|  | ||||
| @ -53,7 +53,7 @@ export class AddonModBookContentsPage implements OnInit, OnDestroy { | ||||
| 
 | ||||
|     @ViewChild(CoreSwipeSlidesComponent) slides?: CoreSwipeSlidesComponent; | ||||
| 
 | ||||
|     title!: string; | ||||
|     title = ''; | ||||
|     cmId!: number; | ||||
|     courseId!: number; | ||||
|     initialChapterId?: number; | ||||
| @ -147,6 +147,8 @@ export class AddonModBookContentsPage implements OnInit, OnDestroy { | ||||
|             } else { | ||||
|                 this.warning = ''; | ||||
|             } | ||||
|         } catch (error) { | ||||
|             CoreDomUtils.showErrorModalDefault(error, 'core.course.errorgetmodule', true); | ||||
|         } finally { | ||||
|             this.loaded = true; | ||||
|         } | ||||
|  | ||||
| @ -1,9 +1,5 @@ | ||||
| <!-- Buttons to add to the header. --> | ||||
| <core-navbar-buttons slot="end"> | ||||
|     <ion-button *ngIf="!showLoading" (click)="showToc()" aria-haspopup="true" [attr.aria-label]="'addon.mod_imscp.toc' | translate"> | ||||
|         <ion-icon name="fas-bookmark" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|     </ion-button> | ||||
| 
 | ||||
|     <ion-button fill="clear" (click)="openModuleSummary()" aria-haspopup="true" [attr.aria-label]="'core.info' | translate"> | ||||
|         <ion-icon name="fas-info-circle" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|     </ion-button> | ||||
| @ -13,24 +9,35 @@ | ||||
| <core-loading [hideUntil]="!showLoading" class="safe-area-padding core-loading-full-height"> | ||||
| 
 | ||||
|     <!-- Activity info. --> | ||||
|     <core-course-module-info [module]="module"> | ||||
|     <core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId" | ||||
|         [courseId]="courseId"> | ||||
|     </core-course-module-info> | ||||
| 
 | ||||
|     <ion-card class="core-warning-card" *ngIf="warning"> | ||||
|     <ion-list> | ||||
|         <ion-item> | ||||
|             <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon> | ||||
|             <ion-label><span [innerHTML]="warning"></span></ion-label> | ||||
|             <ion-label> | ||||
|                 <h2>{{ 'addon.mod_imscp.toc' | translate }}</h2> | ||||
|             </ion-label> | ||||
|         </ion-item> | ||||
|     </ion-card> | ||||
| 
 | ||||
|     <div class="addon-mod-imscp-container"> | ||||
|         <core-iframe *ngIf="!showLoading" [src]="src" [showFullscreenOnToolbar]="true" [autoFullscreenOnRotate]="true"></core-iframe> | ||||
|     </div> | ||||
|         <ion-item class="ion-text-wrap" *ngFor="let item of items" (click)="openImscp(item.href)" button detail="true"> | ||||
|             <ion-label [class.core-bold]="!item.href"> | ||||
|                 <p> | ||||
|                     <span class="ion-padding-start" *ngFor="let i of getNumberForPadding(item.level)"></span> | ||||
|                     {{item.title}} | ||||
|                 </p> | ||||
|             </ion-label> | ||||
|         </ion-item> | ||||
|     </ion-list> | ||||
| 
 | ||||
|     <div collapsible-footer *ngIf="!showLoading" slot="fixed"> | ||||
|         <!-- TODO Add a contents page to avoid having both bars. Please add here start/resume buttons. --> | ||||
|         <core-navigation-bar *ngIf="navigationItems.length > 1" [items]="navigationItems" (action)="loadItem($event)"> | ||||
|         </core-navigation-bar> | ||||
|         <div class="list-item-limited-width"> | ||||
|             <ion-button class="ion-margin ion-text-wrap" expand="block" (click)="openImscp()"> | ||||
|                 <span *ngIf="!hasStarted">{{ 'core.start' | translate }}</span> | ||||
|                 <span *ngIf="hasStarted">{{ 'core.resume' | translate }}</span> | ||||
|             </ion-button> | ||||
|         </div> | ||||
| 
 | ||||
|         <core-course-module-navigation [courseId]="courseId" [currentModule]="module" (completionChanged)="onCompletionChange()"> | ||||
|         </core-course-module-navigation> | ||||
|     </div> | ||||
|  | ||||
| @ -13,14 +13,11 @@ | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { Component, OnInit, Optional } from '@angular/core'; | ||||
| import { CoreSilentError } from '@classes/errors/silenterror'; | ||||
| import { CoreNavigationBarItem } from '@components/navigation-bar/navigation-bar'; | ||||
| import { CoreCourseModuleMainResourceComponent } from '@features/course/classes/main-resource-component'; | ||||
| import { CoreCourseContentsPage } from '@features/course/pages/contents/contents'; | ||||
| import { CoreCourse } from '@features/course/services/course'; | ||||
| import { CoreDomUtils } from '@services/utils/dom'; | ||||
| import { CoreNavigator } from '@services/navigator'; | ||||
| import { AddonModImscpProvider, AddonModImscp, AddonModImscpTocItem } from '../../services/imscp'; | ||||
| import { AddonModImscpTocComponent } from '../toc/toc'; | ||||
| 
 | ||||
| /** | ||||
|  * Component that displays a IMSCP. | ||||
| @ -33,13 +30,9 @@ import { AddonModImscpTocComponent } from '../toc/toc'; | ||||
| export class AddonModImscpIndexComponent extends CoreCourseModuleMainResourceComponent implements OnInit { | ||||
| 
 | ||||
|     component = AddonModImscpProvider.COMPONENT; | ||||
|     src = ''; | ||||
|     warning = ''; | ||||
|     navigationItems: CoreNavigationBarItem<AddonModImscpTocItem>[] = []; | ||||
| 
 | ||||
|     protected items: AddonModImscpTocItem[] = []; | ||||
|     protected currentHref?: string; | ||||
|     protected displayDescription = false; | ||||
|     items: AddonModImscpTocItem[] = []; | ||||
|     hasStarted = false; | ||||
| 
 | ||||
|     constructor(@Optional() courseContentsPage?: CoreCourseContentsPage) { | ||||
|         super('AddonModImscpIndexComponent', courseContentsPage); | ||||
| @ -73,85 +66,67 @@ export class AddonModImscpIndexComponent extends CoreCourseModuleMainResourceCom | ||||
|     /** | ||||
|      * @inheritdoc | ||||
|      */ | ||||
|     protected async fetchContent(refresh = false): Promise<void> { | ||||
|         const downloadResult = await this.downloadResourceIfNeeded(refresh); | ||||
| 
 | ||||
|         const imscp = await AddonModImscp.getImscp(this.courseId, this.module.id); | ||||
|         this.description = imscp.intro; | ||||
|         this.dataRetrieved.emit(imscp); | ||||
| 
 | ||||
|         // Get contents. No need to refresh, it has been done in downloadResourceIfNeeded.
 | ||||
|         const contents = await CoreCourse.getModuleContents(this.module); | ||||
| 
 | ||||
|         this.items = AddonModImscp.createItemList(contents); | ||||
| 
 | ||||
|         if (this.items.length && this.currentHref === undefined) { | ||||
|             this.currentHref = this.items[0].href; | ||||
|         } | ||||
| 
 | ||||
|         try { | ||||
|             await this.loadItemHref(this.currentHref); | ||||
|         } catch (error) { | ||||
|             CoreDomUtils.showErrorModalDefault(error, 'addon.mod_imscp.deploymenterror', true); | ||||
| 
 | ||||
|             throw new CoreSilentError(error); | ||||
|         } | ||||
| 
 | ||||
|         this.warning = downloadResult.failed ? this.getErrorDownloadingSomeFilesMessage(downloadResult.error!) : ''; | ||||
|     protected async fetchContent(): Promise<void> { | ||||
|         await Promise.all([ | ||||
|             this.loadImscp(), | ||||
|             this.loadTOC(), | ||||
|         ]); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Loads an item. | ||||
|      * Load IMSCP data. | ||||
|      * | ||||
|      * @param itemHref Item Href. | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     async loadItemHref(itemHref?: string): Promise<void> { | ||||
|         const src = await AddonModImscp.getIframeSrc(this.module, itemHref); | ||||
|         this.currentHref = itemHref; | ||||
|     protected async loadImscp(): Promise<void> { | ||||
|         const imscp = await AddonModImscp.getImscp(this.courseId, this.module.id); | ||||
| 
 | ||||
|         this.navigationItems = this.items.map((item) => ({ | ||||
|             item: item, | ||||
|             current: item.href == this.currentHref, | ||||
|             enabled: !!item.href, | ||||
|         })); | ||||
|         this.dataRetrieved.emit(imscp); | ||||
| 
 | ||||
|         if (this.src && src == this.src) { | ||||
|             // Re-loading same page. Set it to empty and then re-set the src in the next digest so it detects it has changed.
 | ||||
|             this.src = ''; | ||||
|             setTimeout(() => { | ||||
|                 this.src = src; | ||||
|             }); | ||||
|         } else { | ||||
|             this.src = src; | ||||
|         } | ||||
|         this.dataRetrieved.emit(imscp); | ||||
| 
 | ||||
|         this.description = imscp.intro; | ||||
| 
 | ||||
|         // @todo: Check if user already started the IMSCP.
 | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Loads an item. | ||||
|      * Load book TOC. | ||||
|      * | ||||
|      * @param item Item. | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     loadItem(item: AddonModImscpTocItem): void { | ||||
|         this.loadItemHref(item.href); | ||||
|     protected async loadTOC(): Promise<void> { | ||||
|         // Get contents. No need to refresh, it has been done in downloadResourceIfNeeded.
 | ||||
|         const contents = await CoreCourse.getModuleContents(this.module, this.courseId); | ||||
| 
 | ||||
|         this.items = AddonModImscp.createItemList(contents); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Show the TOC. | ||||
|      * Open IMSCP book with a certain item. | ||||
|      * | ||||
|      * @param href Item href to open, undefined for last item seen. | ||||
|      */ | ||||
|     async showToc(): Promise<void> { | ||||
|         // Create the toc modal.
 | ||||
|         const modalData = await CoreDomUtils.openSideModal<string>({ | ||||
|             component: AddonModImscpTocComponent, | ||||
|             componentProps: { | ||||
|                 items: this.items, | ||||
|                 selected: this.currentHref, | ||||
|     openImscp(href?: string): void { | ||||
|         CoreNavigator.navigate('view', { | ||||
|             params: { | ||||
|                 cmId: this.module.id, | ||||
|                 courseId: this.courseId, | ||||
|                 initialHref: href, | ||||
|             }, | ||||
|         }); | ||||
| 
 | ||||
|         if (modalData) { | ||||
|             this.loadItemHref(modalData); | ||||
|         this.hasStarted = true; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get dummy array for padding. | ||||
|      * | ||||
|      * @param n Array length. | ||||
|      * @return Dummy array with n elements. | ||||
|      */ | ||||
|     getNumberForPadding(n: number): number[] { | ||||
|         return new Array(n); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -24,6 +24,10 @@ const routes: Routes = [ | ||||
|         path: ':courseId/:cmId', | ||||
|         component: AddonModImscpIndexPage, | ||||
|     }, | ||||
|     { | ||||
|         path: ':courseId/:cmId/view', | ||||
|         loadChildren: () => import('./pages/view/view.module').then(m => m.AddonModImscpViewPageModule), | ||||
|     }, | ||||
| ]; | ||||
| 
 | ||||
| @NgModule({ | ||||
|  | ||||
							
								
								
									
										39
									
								
								src/addons/mod/imscp/pages/view/view.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/addons/mod/imscp/pages/view/view.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,39 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
| 
 | ||||
|         <ion-buttons slot="end"> | ||||
|             <ion-button *ngIf="loaded" (click)="showToc()" aria-haspopup="true" [attr.aria-label]="'addon.mod_imscp.toc' | translate"> | ||||
|                 <ion-icon name="fas-bookmark" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|             </ion-button> | ||||
|         </ion-buttons> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|     <!-- Content. --> | ||||
|     <core-loading [hideUntil]="loaded" class="safe-area-padding core-loading-full-height"> | ||||
| 
 | ||||
|         <ion-card class="core-warning-card" *ngIf="warning"> | ||||
|             <ion-item> | ||||
|                 <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-label><span [innerHTML]="warning"></span></ion-label> | ||||
|             </ion-item> | ||||
|         </ion-card> | ||||
| 
 | ||||
|         <div class="addon-mod-imscp-container"> | ||||
|             <core-iframe *ngIf="loaded" [src]="src" [showFullscreenOnToolbar]="true" [autoFullscreenOnRotate]="true"></core-iframe> | ||||
|         </div> | ||||
|     </core-loading> | ||||
| 
 | ||||
|     <core-navigation-bar collapsible-footer *ngIf="loaded && navigationItems.length > 1 && false" [items]="navigationItems" | ||||
|         (action)="loadItem($event)"> | ||||
|     </core-navigation-bar> | ||||
| </ion-content> | ||||
							
								
								
									
										38
									
								
								src/addons/mod/imscp/pages/view/view.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/addons/mod/imscp/pages/view/view.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,38 @@ | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { NgModule } from '@angular/core'; | ||||
| import { RouterModule, Routes } from '@angular/router'; | ||||
| 
 | ||||
| import { CoreSharedModule } from '@/core/shared.module'; | ||||
| import { AddonModImscpViewPage } from './view'; | ||||
| 
 | ||||
| const routes: Routes = [ | ||||
|     { | ||||
|         path: '', | ||||
|         component: AddonModImscpViewPage, | ||||
|     }, | ||||
| ]; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     imports: [ | ||||
|         RouterModule.forChild(routes), | ||||
|         CoreSharedModule, | ||||
|     ], | ||||
|     declarations: [ | ||||
|         AddonModImscpViewPage, | ||||
|     ], | ||||
|     exports: [RouterModule], | ||||
| }) | ||||
| export class AddonModImscpViewPageModule {} | ||||
							
								
								
									
										273
									
								
								src/addons/mod/imscp/pages/view/view.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										273
									
								
								src/addons/mod/imscp/pages/view/view.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,273 @@ | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { CoreConstants } from '@/core/constants'; | ||||
| import { Component, OnInit } from '@angular/core'; | ||||
| import { CoreNavigationBarItem } from '@components/navigation-bar/navigation-bar'; | ||||
| import { CoreCourseResourceDownloadResult } from '@features/course/classes/main-resource-component'; | ||||
| import { CoreCourse } from '@features/course/services/course'; | ||||
| import { CoreCourseModuleData } from '@features/course/services/course-helper'; | ||||
| import { CoreCourseModulePrefetchDelegate } from '@features/course/services/module-prefetch-delegate'; | ||||
| import { IonRefresher } from '@ionic/angular'; | ||||
| import { CoreApp } from '@services/app'; | ||||
| import { CoreNavigator } from '@services/navigator'; | ||||
| import { CoreDomUtils } from '@services/utils/dom'; | ||||
| import { CoreTextUtils } from '@services/utils/text'; | ||||
| import { CoreUtils } from '@services/utils/utils'; | ||||
| import { Translate } from '@singletons'; | ||||
| import { AddonModImscpTocComponent } from '../../components/toc/toc'; | ||||
| import { AddonModImscp, AddonModImscpImscp, AddonModImscpTocItem } from '../../services/imscp'; | ||||
| 
 | ||||
| /** | ||||
|  * Page that displays a IMSCP content. | ||||
|  */ | ||||
| @Component({ | ||||
|     selector: 'page-addon-mod-imscp-view', | ||||
|     templateUrl: 'view.html', | ||||
| }) | ||||
| export class AddonModImscpViewPage implements OnInit { | ||||
| 
 | ||||
|     title = ''; | ||||
|     cmId!: number; | ||||
|     courseId!: number; | ||||
|     initialItemHref?: string; | ||||
|     src = ''; | ||||
|     warning = ''; | ||||
|     navigationItems: CoreNavigationBarItem<AddonModImscpTocItem>[] = []; | ||||
|     loaded = false; | ||||
| 
 | ||||
|     protected module?: CoreCourseModuleData; | ||||
|     protected imscp?: AddonModImscpImscp; | ||||
|     protected items: AddonModImscpTocItem[] = []; | ||||
|     protected currentHref?: string; | ||||
| 
 | ||||
|     /** | ||||
|      * @inheritdoc | ||||
|      */ | ||||
|     ngOnInit(): void { | ||||
|         try { | ||||
|             this.cmId = CoreNavigator.getRequiredRouteNumberParam('cmId'); | ||||
|             this.courseId = CoreNavigator.getRequiredRouteNumberParam('courseId'); | ||||
|             this.initialItemHref = CoreNavigator.getRouteParam('initialHref'); | ||||
|         } catch (error) { | ||||
|             CoreDomUtils.showErrorModal(error); | ||||
| 
 | ||||
|             CoreNavigator.back(); | ||||
| 
 | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         this.fetchContent(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Download IMSCP contents and load the current item. | ||||
|      * | ||||
|      * @param refresh Whether we're refreshing data. | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     protected async fetchContent(refresh = false): Promise<void> { | ||||
|         try { | ||||
|             const { module, imscp } = await this.loadImscpData(); | ||||
| 
 | ||||
|             this.title = imscp.name; | ||||
| 
 | ||||
|             const downloadResult = await this.downloadResourceIfNeeded(module, refresh); | ||||
| 
 | ||||
|             // Get contents. No need to refresh, it has been done in downloadResourceIfNeeded.
 | ||||
|             const contents = await CoreCourse.getModuleContents(module, this.courseId); | ||||
| 
 | ||||
|             this.items = AddonModImscp.createItemList(contents); | ||||
| 
 | ||||
|             if (this.items.length) { | ||||
|                 if (this.initialItemHref) { | ||||
|                     // Check it's valid.
 | ||||
|                     if (this.items.some(item => item.href === this.initialItemHref)) { | ||||
|                         this.currentHref = this.initialItemHref; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 if (this.currentHref === undefined) { | ||||
|                     // @todo: Use last item viewed.
 | ||||
|                     this.currentHref = this.items[0].href; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             try { | ||||
|                 await this.loadItemHref(this.currentHref); | ||||
|             } catch (error) { | ||||
|                 CoreDomUtils.showErrorModalDefault(error, 'addon.mod_imscp.deploymenterror', true); | ||||
| 
 | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             if (downloadResult?.failed) { | ||||
|                 const error = CoreTextUtils.getErrorMessageFromError(downloadResult.error) || downloadResult.error; | ||||
|                 this.warning = Translate.instant('core.errordownloadingsomefiles') + (error ? ' ' + error : ''); | ||||
|             } else { | ||||
|                 this.warning = ''; | ||||
|             } | ||||
|         } catch (error) { | ||||
|             CoreDomUtils.showErrorModalDefault(error, 'core.course.errorgetmodule', true); | ||||
|         } finally { | ||||
|             this.loaded = true; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Load IMSCP data from WS. | ||||
|      * | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     async loadImscpData(): Promise<{ module: CoreCourseModuleData; imscp: AddonModImscpImscp }> { | ||||
|         this.module = await CoreCourse.getModule(this.cmId, this.courseId); | ||||
|         this.imscp = await AddonModImscp.getImscp(this.courseId, this.cmId); | ||||
| 
 | ||||
|         return { | ||||
|             module: this.module, | ||||
|             imscp: this.imscp, | ||||
|         }; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Download a resource if needed. | ||||
|      * If the download call fails the promise won't be rejected, but the error will be included in the returned object. | ||||
|      * If module.contents cannot be loaded then the Promise will be rejected. | ||||
|      * | ||||
|      * @param refresh Whether we're refreshing data. | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     protected async downloadResourceIfNeeded( | ||||
|         module: CoreCourseModuleData, | ||||
|         refresh = false, | ||||
|     ): Promise<CoreCourseResourceDownloadResult> { | ||||
| 
 | ||||
|         const result: CoreCourseResourceDownloadResult = { | ||||
|             failed: false, | ||||
|         }; | ||||
|         let contentsAlreadyLoaded = false; | ||||
| 
 | ||||
|         // Get module status to determine if it needs to be downloaded.
 | ||||
|         const status = await CoreCourseModulePrefetchDelegate.getModuleStatus(module, this.courseId, undefined, refresh); | ||||
| 
 | ||||
|         if (status !== CoreConstants.DOWNLOADED) { | ||||
|             // Download content. This function also loads module contents if needed.
 | ||||
|             try { | ||||
|                 await CoreCourseModulePrefetchDelegate.downloadModule(module, this.courseId); | ||||
| 
 | ||||
|                 // If we reach here it means the download process already loaded the contents, no need to do it again.
 | ||||
|                 contentsAlreadyLoaded = true; | ||||
|             } catch (error) { | ||||
|                 // Mark download as failed but go on since the main files could have been downloaded.
 | ||||
|                 result.failed = true; | ||||
|                 result.error = error; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (!module.contents?.length || (refresh && !contentsAlreadyLoaded)) { | ||||
|             // Try to load the contents.
 | ||||
|             const ignoreCache = refresh && CoreApp.isOnline(); | ||||
| 
 | ||||
|             try { | ||||
|                 await CoreCourse.loadModuleContents(module, undefined, undefined, false, ignoreCache); | ||||
|             } catch (error) { | ||||
|                 // Error loading contents. If we ignored cache, try to get the cached value.
 | ||||
|                 if (ignoreCache && !module.contents) { | ||||
|                     await CoreCourse.loadModuleContents(module); | ||||
|                 } else if (!module.contents) { | ||||
|                     // Not able to load contents, throw the error.
 | ||||
|                     throw error; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Refresh the data. | ||||
|      * | ||||
|      * @param refresher Refresher. | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     async doRefresh(refresher?: IonRefresher): Promise<void> { | ||||
|         await CoreUtils.ignoreErrors(Promise.all([ | ||||
|             AddonModImscp.invalidateContent(this.cmId, this.courseId), | ||||
|             CoreCourseModulePrefetchDelegate.invalidateCourseUpdates(this.courseId), // To detect if IMSCP was updated.
 | ||||
|         ])); | ||||
| 
 | ||||
|         await CoreUtils.ignoreErrors(this.fetchContent(true)); | ||||
| 
 | ||||
|         refresher?.complete(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Loads an item. | ||||
|      * | ||||
|      * @param itemHref Item Href. | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     async loadItemHref(itemHref?: string): Promise<void> { | ||||
|         if (!this.module) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         const src = await AddonModImscp.getIframeSrc(this.module, itemHref); | ||||
|         this.currentHref = itemHref; | ||||
| 
 | ||||
|         this.navigationItems = this.items.map((item) => ({ | ||||
|             item: item, | ||||
|             current: item.href == this.currentHref, | ||||
|             enabled: !!item.href, | ||||
|         })); | ||||
| 
 | ||||
|         if (this.src && src == this.src) { | ||||
|             // Re-loading same page. Set it to empty and then re-set the src in the next digest so it detects it has changed.
 | ||||
|             this.src = ''; | ||||
|             setTimeout(() => { | ||||
|                 this.src = src; | ||||
|             }); | ||||
|         } else { | ||||
|             this.src = src; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Loads an item. | ||||
|      * | ||||
|      * @param item Item. | ||||
|      */ | ||||
|     loadItem(item: AddonModImscpTocItem): void { | ||||
|         this.loadItemHref(item.href); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Show the TOC. | ||||
|      */ | ||||
|     async showToc(): Promise<void> { | ||||
|         // Create the toc modal.
 | ||||
|         const modalData = await CoreDomUtils.openSideModal<string>({ | ||||
|             component: AddonModImscpTocComponent, | ||||
|             componentProps: { | ||||
|                 items: this.items, | ||||
|                 selected: this.currentHref, | ||||
|             }, | ||||
|         }); | ||||
| 
 | ||||
|         if (modalData) { | ||||
|             this.loadItemHref(modalData); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user