forked from EVOgeek/Vmeda.Online
		
	MOBILE-3931 module: Adapt module site plugins code
This commit is contained in:
		
							parent
							
								
									16cee9df14
								
							
						
					
					
						commit
						6c782e3b3e
					
				| @ -58,7 +58,6 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy, | |||||||
|     hasOffline = false; // Resources don't have any data to sync.
 |     hasOffline = false; // Resources don't have any data to sync.
 | ||||||
| 
 | 
 | ||||||
|     description?: string; // Module description.
 |     description?: string; // Module description.
 | ||||||
|     isDestroyed = false; // Whether the component is destroyed.
 |  | ||||||
| 
 | 
 | ||||||
|     protected fetchContentDefaultError = 'core.course.errorgetmodule'; // Default error to show when loading contents.
 |     protected fetchContentDefaultError = 'core.course.errorgetmodule'; // Default error to show when loading contents.
 | ||||||
|     protected isCurrentView = false; // Whether the component is in the current view.
 |     protected isCurrentView = false; // Whether the component is in the current view.
 | ||||||
| @ -72,6 +71,7 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy, | |||||||
|     protected debouncedUpdateModule?: () => void; // Update the module after a certain time.
 |     protected debouncedUpdateModule?: () => void; // Update the module after a certain time.
 | ||||||
|     protected showCompletion = false; // Whether to show completion inside the activity.
 |     protected showCompletion = false; // Whether to show completion inside the activity.
 | ||||||
|     protected displayDescription = true; // Wether to show Module description on module page, and not on summary or the contrary.
 |     protected displayDescription = true; // Wether to show Module description on module page, and not on summary or the contrary.
 | ||||||
|  |     protected isDestroyed = false; // Whether the component is destroyed.
 | ||||||
| 
 | 
 | ||||||
|     constructor( |     constructor( | ||||||
|         @Optional() @Inject('') loggerName: string = 'CoreCourseModuleMainResourceComponent', |         @Optional() @Inject('') loggerName: string = 'CoreCourseModuleMainResourceComponent', | ||||||
| @ -111,11 +111,10 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy, | |||||||
|      * Refresh the data. |      * Refresh the data. | ||||||
|      * |      * | ||||||
|      * @param refresher Refresher. |      * @param refresher Refresher. | ||||||
|      * @param done Function to call when done. Never used. |  | ||||||
|      * @param showErrors If show errors to the user of hide them. |      * @param showErrors If show errors to the user of hide them. | ||||||
|      * @return Promise resolved when done. |      * @return Promise resolved when done. | ||||||
|      */ |      */ | ||||||
|     async doRefresh(refresher?: IonRefresher | null, done?: () => void, showErrors: boolean = false): Promise<void> { |     async doRefresh(refresher?: IonRefresher | null, showErrors = false): Promise<void> { | ||||||
|         if (!this.loaded || !this.module) { |         if (!this.loaded || !this.module) { | ||||||
|             // Module can be undefined if course format changes from single activity to weekly/topics.
 |             // Module can be undefined if course format changes from single activity to weekly/topics.
 | ||||||
|             return; |             return; | ||||||
| @ -405,10 +404,14 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy, | |||||||
|             componentProps: { |             componentProps: { | ||||||
|                 moduleId: this.module.id, |                 moduleId: this.module.id, | ||||||
|                 module: this.module, |                 module: this.module, | ||||||
|                 description: !this.displayDescription ? this.description : '', |                 description: this.description, | ||||||
|                 component: this.component, |                 component: this.component, | ||||||
|                 courseId: this.courseId, |                 courseId: this.courseId, | ||||||
|                 hasOffline: this.hasOffline, |                 hasOffline: this.hasOffline, | ||||||
|  |                 displayOptions: { | ||||||
|  |                     // Show description on summary if not shown on the page.
 | ||||||
|  |                     displayDescription: !this.displayDescription, | ||||||
|  |                 }, | ||||||
|             }, |             }, | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
| @ -421,11 +424,11 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy, | |||||||
|                 } finally { |                 } finally { | ||||||
|                     modal.dismiss(); |                     modal.dismiss(); | ||||||
|                 } |                 } | ||||||
|             } else if(data.action == 'sync') { |             } else if (data.action == 'sync') { | ||||||
|                 const modal = await CoreDomUtils.showModalLoading(); |                 const modal = await CoreDomUtils.showModalLoading(); | ||||||
| 
 | 
 | ||||||
|                 try { |                 try { | ||||||
|                     await this.doRefresh( undefined, undefined, true); |                     await this.doRefresh( undefined, true); | ||||||
|                 } finally { |                 } finally { | ||||||
|                     modal.dismiss(); |                     modal.dismiss(); | ||||||
|                 } |                 } | ||||||
|  | |||||||
| @ -19,12 +19,12 @@ | |||||||
|                     </core-format-text> |                     </core-format-text> | ||||||
|                 </h1> |                 </h1> | ||||||
|             </ion-label> |             </ion-label> | ||||||
|             <ion-button fill="clear" [href]="externalUrl" core-link [showBrowserWarning]="false" color="dark" |             <ion-button fill="clear" *ngIf="displayOptions.displayOpenInBrowser" [href]="externalUrl" core-link [showBrowserWarning]="false" | ||||||
|                 [attr.aria-label]="'core.openinbrowser' | translate" slot="end"> |                 color="dark" [attr.aria-label]="'core.openinbrowser' | translate" slot="end"> | ||||||
|                 <ion-icon name="fas-external-link-alt" slot="icon-only" aria-hidden="true"></ion-icon> |                 <ion-icon name="fas-external-link-alt" slot="icon-only" aria-hidden="true"></ion-icon> | ||||||
|             </ion-button> |             </ion-button> | ||||||
|         </ion-item> |         </ion-item> | ||||||
|         <ion-item class="ion-text-wrap" *ngIf="module && description"> |         <ion-item class="ion-text-wrap" *ngIf="module && description && displayOptions.displayDescription"> | ||||||
|             <ion-label> |             <ion-label> | ||||||
|                 <core-format-text [text]="description" [component]="component" [componentId]="componentId" contextLevel="module" |                 <core-format-text [text]="description" [component]="component" [componentId]="componentId" contextLevel="module" | ||||||
|                     [contextInstanceId]="module.id" [courseId]="courseId" [maxHeight]="120"> |                     [contextInstanceId]="module.id" [courseId]="courseId" [maxHeight]="120"> | ||||||
| @ -32,7 +32,7 @@ | |||||||
|             </ion-label> |             </ion-label> | ||||||
|         </ion-item> |         </ion-item> | ||||||
| 
 | 
 | ||||||
|         <ion-item button class="ion-margin" *ngIf="prefetchText" class="ion-text-wrap"> |         <ion-item button class="ion-margin" *ngIf="prefetchText && displayOptions.displayPrefetch" class="ion-text-wrap"> | ||||||
|             <ion-label> |             <ion-label> | ||||||
|                 <p class="item-heading ion-text-wrap">{{ prefetchText }}</p> |                 <p class="item-heading ion-text-wrap">{{ prefetchText }}</p> | ||||||
|                 <p *ngIf="downloadTimeReadable">{{ downloadTimeReadable }}</p> |                 <p *ngIf="downloadTimeReadable">{{ downloadTimeReadable }}</p> | ||||||
| @ -45,7 +45,7 @@ | |||||||
|             <ion-spinner *ngIf="prefetchStatusIcon == 'spinner'" slot="end" aria-hidden="true"></ion-spinner> |             <ion-spinner *ngIf="prefetchStatusIcon == 'spinner'" slot="end" aria-hidden="true"></ion-spinner> | ||||||
|         </ion-item> |         </ion-item> | ||||||
| 
 | 
 | ||||||
|         <ion-item button class="ion-margin" *ngIf="sizeReadable" class="ion-text-wrap"> |         <ion-item button class="ion-margin" *ngIf="sizeReadable && displayOptions.displaySize" class="ion-text-wrap"> | ||||||
|             <ion-label> |             <ion-label> | ||||||
|                 <p class="item-heading ion-text-wrap">{{ 'addon.storagemanager.totalspaceusage' | translate }}</p> |                 <p class="item-heading ion-text-wrap">{{ 'addon.storagemanager.totalspaceusage' | translate }}</p> | ||||||
|                 <ion-badge color="light">{{ sizeReadable | coreBytesToSize }}</ion-badge> |                 <ion-badge color="light">{{ sizeReadable | coreBytesToSize }}</ion-badge> | ||||||
| @ -57,7 +57,7 @@ | |||||||
|             <ion-spinner *ngIf="removeFilesLoading" slot="end" aria-hidden="true"></ion-spinner> |             <ion-spinner *ngIf="removeFilesLoading" slot="end" aria-hidden="true"></ion-spinner> | ||||||
|         </ion-item> |         </ion-item> | ||||||
| 
 | 
 | ||||||
|         <ion-button *ngIf="blog" class="ion-margin" (click)="gotoBlog()" expand="block" fill="outline"> |         <ion-button *ngIf="blog && displayOptions.displayBlog" class="ion-margin" (click)="gotoBlog()" expand="block" fill="outline"> | ||||||
|             <ion-icon name="far-newspaper" slot="start" aria-hidden="true"></ion-icon> |             <ion-icon name="far-newspaper" slot="start" aria-hidden="true"></ion-icon> | ||||||
|             <ion-label> |             <ion-label> | ||||||
|                 {{ 'addon.blog.blog' | translate }} |                 {{ 'addon.blog.blog' | translate }} | ||||||
| @ -65,7 +65,7 @@ | |||||||
|         </ion-button> |         </ion-button> | ||||||
|     </core-loading> |     </core-loading> | ||||||
| </ion-content> | </ion-content> | ||||||
| <ion-footer *ngIf="loaded && isOnline"> | <ion-footer *ngIf="loaded && isOnline && displayOptions.displayRefresh"> | ||||||
|     <ion-button class="ion-margin" *ngIf="!hasOffline" (click)="refresh()" expand="block"> |     <ion-button class="ion-margin" *ngIf="!hasOffline" (click)="refresh()" expand="block"> | ||||||
|         <ion-icon name="fas-redo-alt" slot="start" aria-hidden="true"></ion-icon> |         <ion-icon name="fas-redo-alt" slot="start" aria-hidden="true"></ion-icon> | ||||||
|         <ion-label> |         <ion-label> | ||||||
|  | |||||||
| @ -46,6 +46,7 @@ export class CoreCourseModuleSummaryComponent implements OnInit, OnDestroy { | |||||||
|     @Input() component = ''; // Component name.
 |     @Input() component = ''; // Component name.
 | ||||||
|     @Input() description = ''; // Module description.
 |     @Input() description = ''; // Module description.
 | ||||||
|     @Input() hasOffline = false; // If it has offline data to be synced.
 |     @Input() hasOffline = false; // If it has offline data to be synced.
 | ||||||
|  |     @Input() displayOptions: CoreCourseModuleSummaryDisplayOptions = {}; | ||||||
| 
 | 
 | ||||||
|     loaded = false; // If the component has been loaded.
 |     loaded = false; // If the component has been loaded.
 | ||||||
|     componentId?: number; // Component ID.
 |     componentId?: number; // Component ID.
 | ||||||
| @ -95,6 +96,15 @@ export class CoreCourseModuleSummaryComponent implements OnInit, OnDestroy { | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         this.displayOptions = Object.assign({ | ||||||
|  |             displayOpenInBrowser: true, | ||||||
|  |             displayDescription: true, | ||||||
|  |             displayRefresh: true, | ||||||
|  |             displayPrefetch: true, | ||||||
|  |             displaySize: true, | ||||||
|  |             displayBlog: true, | ||||||
|  |         }, this.displayOptions); | ||||||
|  | 
 | ||||||
|         this.fetchContent(); |         this.fetchContent(); | ||||||
| 
 | 
 | ||||||
|         if (this.component) { |         if (this.component) { | ||||||
| @ -306,6 +316,15 @@ export class CoreCourseModuleSummaryComponent implements OnInit, OnDestroy { | |||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export type CoreCourseModuleSummaryResult =  { | export type CoreCourseModuleSummaryResult = { | ||||||
|     action: 'sync'|'refresh'; |     action: 'sync'|'refresh'; | ||||||
| }; | }; | ||||||
|  | 
 | ||||||
|  | export type CoreCourseModuleSummaryDisplayOptions = { | ||||||
|  |     displayOpenInBrowser?: boolean; | ||||||
|  |     displayDescription?: boolean; | ||||||
|  |     displayRefresh?: boolean; | ||||||
|  |     displayPrefetch?: boolean; | ||||||
|  |     displaySize?: boolean; | ||||||
|  |     displayBlog?: boolean; | ||||||
|  | }; | ||||||
|  | |||||||
| @ -64,7 +64,6 @@ import { CoreFile } from '@services/file'; | |||||||
| import { CoreUrlUtils } from '@services/utils/url'; | import { CoreUrlUtils } from '@services/utils/url'; | ||||||
| import { CoreTextUtils } from '@services/utils/text'; | import { CoreTextUtils } from '@services/utils/text'; | ||||||
| import { CoreTimeUtils } from '@services/utils/time'; | import { CoreTimeUtils } from '@services/utils/time'; | ||||||
| import { CoreEventObserver, CoreEvents } from '@singletons/events'; |  | ||||||
| import { CoreFilterHelper } from '@features/filter/services/filter-helper'; | import { CoreFilterHelper } from '@features/filter/services/filter-helper'; | ||||||
| import { CoreNetworkError } from '@classes/errors/network-error'; | import { CoreNetworkError } from '@classes/errors/network-error'; | ||||||
| import { CoreSiteHome } from '@features/sitehome/services/sitehome'; | import { CoreSiteHome } from '@features/sitehome/services/sitehome'; | ||||||
| @ -474,23 +473,18 @@ export class CoreCourseHelperProvider { | |||||||
|      * |      * | ||||||
|      * @param module Module to remove the files. |      * @param module Module to remove the files. | ||||||
|      * @param courseId Course ID the module belongs to. |      * @param courseId Course ID the module belongs to. | ||||||
|      * @param done Function to call when done. It will close the context menu. |  | ||||||
|      * @return Promise resolved when done. |      * @return Promise resolved when done. | ||||||
|      * @deprecated since 4.0 |      * @deprecated since 4.0 | ||||||
|      */ |      */ | ||||||
|     async confirmAndRemoveFiles(module: CoreCourseModuleData, courseId: number, done?: () => void): Promise<void> { |     async confirmAndRemoveFiles(module: CoreCourseModuleData, courseId: number): Promise<void> { | ||||||
|         let modal: CoreIonLoadingElement | undefined; |         let modal: CoreIonLoadingElement | undefined; | ||||||
| 
 | 
 | ||||||
|         try { |         try { | ||||||
| 
 |  | ||||||
|             await CoreDomUtils.showDeleteConfirm('addon.storagemanager.confirmdeletedatafrom', { name: module.name }); |             await CoreDomUtils.showDeleteConfirm('addon.storagemanager.confirmdeletedatafrom', { name: module.name }); | ||||||
| 
 | 
 | ||||||
|             modal = await CoreDomUtils.showModalLoading(); |             modal = await CoreDomUtils.showModalLoading(); | ||||||
| 
 | 
 | ||||||
|             await this.removeModuleStoredData(module, courseId); |             await this.removeModuleStoredData(module, courseId); | ||||||
| 
 |  | ||||||
|             done && done(); |  | ||||||
| 
 |  | ||||||
|         } catch (error) { |         } catch (error) { | ||||||
|             if (error) { |             if (error) { | ||||||
|                 CoreDomUtils.showErrorModal(error); |                 CoreDomUtils.showErrorModal(error); | ||||||
| @ -555,45 +549,6 @@ export class CoreCourseHelperProvider { | |||||||
|         await CoreDomUtils.confirmDownloadSize(sizeSum, undefined, undefined, undefined, undefined, alwaysConfirm); |         await CoreDomUtils.confirmDownloadSize(sizeSum, undefined, undefined, undefined, undefined, alwaysConfirm); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * Helper function to prefetch a module, showing a confirmation modal if the size is big. |  | ||||||
|      * This function is meant to be called from a context menu option. It will also modify some data like the prefetch icon. |  | ||||||
|      * |  | ||||||
|      * @param instance The component instance that has the context menu. |  | ||||||
|      * @param module Module to be prefetched |  | ||||||
|      * @param courseId Course ID the module belongs to. |  | ||||||
|      * @param done Function to call when done. It will close the context menu. |  | ||||||
|      * @return Promise resolved when done. |  | ||||||
|      * @deprecated since 4.0 |  | ||||||
|      */ |  | ||||||
|     async contextMenuPrefetch( |  | ||||||
|         instance: ComponentWithContextMenu, |  | ||||||
|         module: CoreCourseModuleData, |  | ||||||
|         courseId: number, |  | ||||||
|         done?: () => void, |  | ||||||
|     ): Promise<void> { |  | ||||||
|         const initialIcon = instance.prefetchStatusIcon; |  | ||||||
|         instance.prefetchStatusIcon = CoreConstants.ICON_DOWNLOADING; // Show spinner since this operation might take a while.
 |  | ||||||
| 
 |  | ||||||
|         try { |  | ||||||
|             // We need to call getDownloadSize, the package might have been updated.
 |  | ||||||
|             const size = await CoreCourseModulePrefetchDelegate.getModuleDownloadSize(module, courseId, true); |  | ||||||
| 
 |  | ||||||
|             await CoreDomUtils.confirmDownloadSize(size); |  | ||||||
| 
 |  | ||||||
|             await CoreCourseModulePrefetchDelegate.prefetchModule(module, courseId, true); |  | ||||||
| 
 |  | ||||||
|             // Success, close menu.
 |  | ||||||
|             done && done(); |  | ||||||
|         } catch (error) { |  | ||||||
|             instance.prefetchStatusIcon = initialIcon; |  | ||||||
| 
 |  | ||||||
|             if (!instance.isDestroyed) { |  | ||||||
|                 CoreDomUtils.showErrorModalDefault(error, 'core.errordownloading', true); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |     /** | ||||||
|      * Check whether a course is accessed using guest access. |      * Check whether a course is accessed using guest access. | ||||||
|      * |      * | ||||||
| @ -1030,87 +985,6 @@ export class CoreCourseHelperProvider { | |||||||
|         await CoreFilepool.downloadOrPrefetchFiles(siteId, files, false, false, component, componentId); |         await CoreFilepool.downloadOrPrefetchFiles(siteId, files, false, false, component, componentId); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * Fill the Context Menu for a certain module. |  | ||||||
|      * |  | ||||||
|      * @param instance The component instance that has the context menu. |  | ||||||
|      * @param module Module to be prefetched |  | ||||||
|      * @param courseId Course ID the module belongs to. |  | ||||||
|      * @param invalidateCache Invalidates the cache first. |  | ||||||
|      * @param component Component of the module. |  | ||||||
|      * @return Promise resolved when done. |  | ||||||
|      */ |  | ||||||
|     async fillContextMenu( |  | ||||||
|         instance: ComponentWithContextMenu, |  | ||||||
|         module: CoreCourseModuleData, |  | ||||||
|         courseId: number, |  | ||||||
|         invalidateCache?: boolean, |  | ||||||
|         component?: string, |  | ||||||
|     ): Promise<void> { |  | ||||||
|         const siteId = CoreSites.getCurrentSiteId(); |  | ||||||
| 
 |  | ||||||
|         const moduleInfo = await this.getModulePrefetchInfo(module, courseId, invalidateCache, component); |  | ||||||
| 
 |  | ||||||
|         instance.size = moduleInfo.sizeReadable; |  | ||||||
|         instance.prefetchStatusIcon = moduleInfo.statusIcon; |  | ||||||
|         instance.prefetchStatus = moduleInfo.status; |  | ||||||
|         instance.downloadTimeReadable = CoreTextUtils.ucFirst(moduleInfo.downloadTimeReadable); |  | ||||||
| 
 |  | ||||||
|         if (moduleInfo.status != CoreConstants.NOT_DOWNLOADABLE) { |  | ||||||
|             // Module is downloadable, get the text to display to prefetch.
 |  | ||||||
|             if (moduleInfo.downloadTime && moduleInfo.downloadTime > 0) { |  | ||||||
|                 instance.prefetchText = Translate.instant('core.lastdownloaded') + ': ' + moduleInfo.downloadTimeReadable; |  | ||||||
|             } else { |  | ||||||
|                 // Module not downloaded, show a default text.
 |  | ||||||
|                 instance.prefetchText = Translate.instant('core.download'); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if (moduleInfo.status == CoreConstants.DOWNLOADING) { |  | ||||||
|             // Set this to empty to prevent "remove file" option showing up while downloading.
 |  | ||||||
|             instance.size = ''; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if (!instance.contextMenuStatusObserver && component) { |  | ||||||
|             instance.contextMenuStatusObserver = CoreEvents.on( |  | ||||||
|                 CoreEvents.PACKAGE_STATUS_CHANGED, |  | ||||||
|                 (data) => { |  | ||||||
|                     if (data.componentId == module.id && data.component == component) { |  | ||||||
|                         this.fillContextMenu(instance, module, courseId, false, component); |  | ||||||
|                     } |  | ||||||
|                 }, |  | ||||||
|                 siteId, |  | ||||||
|             ); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if (!instance.contextFileStatusObserver && component) { |  | ||||||
|             // Debounce the update size function to prevent too many calls when downloading or deleting a whole activity.
 |  | ||||||
|             const debouncedUpdateSize = CoreUtils.debounce(async () => { |  | ||||||
|                 const moduleSize = await CoreCourseModulePrefetchDelegate.getModuleStoredSize(module, courseId); |  | ||||||
| 
 |  | ||||||
|                 instance.size = moduleSize > 0 ? CoreTextUtils.bytesToSize(moduleSize, 2) : ''; |  | ||||||
|             }, 1000); |  | ||||||
| 
 |  | ||||||
|             instance.contextFileStatusObserver = CoreEvents.on( |  | ||||||
|                 CoreEvents.COMPONENT_FILE_ACTION, |  | ||||||
|                 (data) => { |  | ||||||
|                     if (data.component != component || data.componentId != module.id) { |  | ||||||
|                         // The event doesn't belong to this component, ignore.
 |  | ||||||
|                         return; |  | ||||||
|                     } |  | ||||||
| 
 |  | ||||||
|                     if (!CoreFilepool.isFileEventDownloadedOrDeleted(data)) { |  | ||||||
|                         return; |  | ||||||
|                     } |  | ||||||
| 
 |  | ||||||
|                     // Update the module size.
 |  | ||||||
|                     debouncedUpdateSize(); |  | ||||||
|                 }, |  | ||||||
|                 siteId, |  | ||||||
|             ); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |     /** | ||||||
|      * Get a course. It will first check the user courses, and fallback to another WS if not enrolled. |      * Get a course. It will first check the user courses, and fallback to another WS if not enrolled. | ||||||
|      * |      * | ||||||
| @ -2225,14 +2099,3 @@ export type CoreCourseOpenModuleOptions = { | |||||||
|     sectionId?: number; // Section the module belongs to.
 |     sectionId?: number; // Section the module belongs to.
 | ||||||
|     modNavOptions?: CoreNavigationOptions; // Navigation options to open the module, including params to pass to the module.
 |     modNavOptions?: CoreNavigationOptions; // Navigation options to open the module, including params to pass to the module.
 | ||||||
| }; | }; | ||||||
| 
 |  | ||||||
| type ComponentWithContextMenu = { |  | ||||||
|     prefetchStatusIcon?: string; |  | ||||||
|     isDestroyed?: boolean; |  | ||||||
|     size?: string; |  | ||||||
|     prefetchStatus?: string; |  | ||||||
|     prefetchText?: string; |  | ||||||
|     downloadTimeReadable?: string; |  | ||||||
|     contextMenuStatusObserver?: CoreEventObserver; |  | ||||||
|     contextFileStatusObserver?: CoreEventObserver; |  | ||||||
| }; |  | ||||||
|  | |||||||
| @ -202,10 +202,10 @@ export interface CoreCourseModuleMainComponent { | |||||||
|      * Refresh the data. |      * Refresh the data. | ||||||
|      * |      * | ||||||
|      * @param refresher Refresher. |      * @param refresher Refresher. | ||||||
|      * @param done Function to call when done. |      * @param showErrors If show errors to the user of hide them. | ||||||
|      * @return Promise resolved when done. |      * @return Promise resolved when done. | ||||||
|      */ |      */ | ||||||
|     doRefresh(refresher?: IonRefresher, done?: () => void): Promise<void>; |     doRefresh(refresher?: IonRefresher | null, showErrors?: boolean): Promise<void>; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  | |||||||
| @ -1,28 +1,8 @@ | |||||||
| <!-- Buttons to add to the header. --> | <!-- Buttons to add to the header. --> | ||||||
| <core-navbar-buttons slot="end"> | <core-navbar-buttons slot="end"> | ||||||
|     <core-context-menu> |     <ion-button fill="clear" (click)="openModuleSummary()" [attr.aria-label]="'core.info' | translate"> | ||||||
|         <core-context-menu-item [hidden]="!displayOpenInBrowser || !externalUrl || ( |         <ion-icon name="fas-info-circle" slot="icon-only" aria-hidden="true"></ion-icon> | ||||||
|             content?.compileComponent?.componentInstance?.displayOpenInBrowser === false)" [priority]="900" |     </ion-button> | ||||||
|             [content]="'core.openinbrowser' | translate" [href]="externalUrl" iconAction="fas-external-link-alt"> |  | ||||||
|         </core-context-menu-item> |  | ||||||
|         <core-context-menu-item [hidden]="!displayDescription || !description || ( |  | ||||||
|             content?.compileComponent?.componentInstance?.displayDescription === false)" [priority]="800" |  | ||||||
|             [content]="'core.moduleintro' | translate" (action)="expandDescription()" iconAction="fas-arrow-right"> |  | ||||||
|         </core-context-menu-item> |  | ||||||
|         <core-context-menu-item [hidden]="!displayRefresh || ( |  | ||||||
|             content?.compileComponent?.componentInstance?.displayRefresh === false)" [priority]="700" |  | ||||||
|             [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"> |  | ||||||
|         </core-context-menu-item> |  | ||||||
|         <core-context-menu-item [hidden]="!displayPrefetch || !prefetchStatusIcon || ( |  | ||||||
|             content?.compileComponent?.componentInstance?.displayPrefetch === false)" [priority]="600" [content]="prefetchText" |  | ||||||
|             (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"> |  | ||||||
|         </core-context-menu-item> |  | ||||||
|         <core-context-menu-item [hidden]="!displaySize || !size || ( |  | ||||||
|             content?.compileComponent?.componentInstance?.displaySize === false)" [priority]="500" |  | ||||||
|             [content]="'core.clearstoreddata' | translate:{$a: size}" [iconDescription]="'fas-archive'" (action)="removeFiles()" |  | ||||||
|             iconAction="fas-trash" [closeOnClick]="false"> |  | ||||||
|         </core-context-menu-item> |  | ||||||
|     </core-context-menu> |  | ||||||
| </core-navbar-buttons> | </core-navbar-buttons> | ||||||
| 
 | 
 | ||||||
| <core-site-plugins-plugin-content *ngIf="component && method" [component]="component" [method]="method" [args]="args" | <core-site-plugins-plugin-content *ngIf="component && method" [component]="component" [method]="method" [args]="args" | ||||||
|  | |||||||
| @ -14,8 +14,13 @@ | |||||||
| 
 | 
 | ||||||
| import { CoreConstants } from '@/core/constants'; | import { CoreConstants } from '@/core/constants'; | ||||||
| import { Component, OnInit, OnDestroy, Input, ViewChild } from '@angular/core'; | import { Component, OnInit, OnDestroy, Input, ViewChild } from '@angular/core'; | ||||||
|  | import { CoreIonLoadingElement } from '@classes/ion-loading'; | ||||||
| 
 | 
 | ||||||
| import { CoreSiteWSPreSets } from '@classes/site'; | import { CoreSiteWSPreSets } from '@classes/site'; | ||||||
|  | import { | ||||||
|  |     CoreCourseModuleSummaryResult, | ||||||
|  |     CoreCourseModuleSummaryComponent, | ||||||
|  | } from '@features/course/components/module-summary/module-summary'; | ||||||
| import { CoreCourseHelper, CoreCourseModuleData } from '@features/course/services/course-helper'; | import { CoreCourseHelper, CoreCourseModuleData } from '@features/course/services/course-helper'; | ||||||
| import { | import { | ||||||
|     CoreCourseModuleDelegate, |     CoreCourseModuleDelegate, | ||||||
| @ -28,10 +33,8 @@ import { | |||||||
|     CoreSitePluginsCourseModuleHandlerData, |     CoreSitePluginsCourseModuleHandlerData, | ||||||
| } from '@features/siteplugins/services/siteplugins'; | } from '@features/siteplugins/services/siteplugins'; | ||||||
| import { IonRefresher } from '@ionic/angular'; | import { IonRefresher } from '@ionic/angular'; | ||||||
| import { CoreTextUtils } from '@services/utils/text'; | import { CoreDomUtils } from '@services/utils/dom'; | ||||||
| import { CoreUtils } from '@services/utils/utils'; | import { CoreUtils } from '@services/utils/utils'; | ||||||
| import { Translate } from '@singletons'; |  | ||||||
| import { CoreEventObserver } from '@singletons/events'; |  | ||||||
| import { CoreSitePluginsPluginContentComponent } from '../plugin-content/plugin-content'; | import { CoreSitePluginsPluginContentComponent } from '../plugin-content/plugin-content'; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
| @ -55,22 +58,39 @@ export class CoreSitePluginsModuleIndexComponent implements OnInit, OnDestroy, C | |||||||
|     args?: Record<string, unknown>; |     args?: Record<string, unknown>; | ||||||
|     initResult?: CoreSitePluginsContent | null; |     initResult?: CoreSitePluginsContent | null; | ||||||
|     preSets?: CoreSiteWSPreSets; |     preSets?: CoreSiteWSPreSets; | ||||||
| 
 |  | ||||||
|     // Data for context menu.
 |  | ||||||
|     externalUrl?: string; |  | ||||||
|     description?: string; |     description?: string; | ||||||
|     refreshIcon?: string; | 
 | ||||||
|  |     /** | ||||||
|  |      * @deprecated since 4.0, use module.url instead. | ||||||
|  |      */ | ||||||
|  |     externalUrl?: string; | ||||||
|  |     /** | ||||||
|  |      * @deprecated since 4.0. It won't be populated anymore. | ||||||
|  |      */ | ||||||
|  |     refreshIcon = CoreConstants.ICON_REFRESH; | ||||||
|  |     /** | ||||||
|  |      * @deprecated since 4.0.. It won't be populated anymore. | ||||||
|  |      */ | ||||||
|     prefetchStatus?: string; |     prefetchStatus?: string; | ||||||
|  |     /** | ||||||
|  |      * @deprecated since 4.0. It won't be populated anymore. | ||||||
|  |      */ | ||||||
|     prefetchStatusIcon?: string; |     prefetchStatusIcon?: string; | ||||||
|  |     /** | ||||||
|  |      * @deprecated since 4.0. It won't be populated anymore. | ||||||
|  |      */ | ||||||
|     prefetchText?: string; |     prefetchText?: string; | ||||||
|  |     /** | ||||||
|  |      * @deprecated since 4.0. It won't be populated anymore. | ||||||
|  |      */ | ||||||
|     size?: string; |     size?: string; | ||||||
|     contextMenuStatusObserver?: CoreEventObserver; | 
 | ||||||
|     contextFileStatusObserver?: CoreEventObserver; |  | ||||||
|     displayOpenInBrowser = true; |     displayOpenInBrowser = true; | ||||||
|     displayDescription = true; |     displayDescription = true; | ||||||
|     displayRefresh = true; |     displayRefresh = true; | ||||||
|     displayPrefetch = true; |     displayPrefetch = true; | ||||||
|     displaySize = true; |     displaySize = true; | ||||||
|  | 
 | ||||||
|     ptrEnabled = true; |     ptrEnabled = true; | ||||||
|     isDestroyed = false; |     isDestroyed = false; | ||||||
| 
 | 
 | ||||||
| @ -80,8 +100,6 @@ export class CoreSitePluginsModuleIndexComponent implements OnInit, OnDestroy, C | |||||||
|      * Component being initialized. |      * Component being initialized. | ||||||
|      */ |      */ | ||||||
|     ngOnInit(): void { |     ngOnInit(): void { | ||||||
|         this.refreshIcon = CoreConstants.ICON_LOADING; |  | ||||||
| 
 |  | ||||||
|         if (!this.module) { |         if (!this.module) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| @ -122,71 +140,119 @@ export class CoreSitePluginsModuleIndexComponent implements OnInit, OnDestroy, C | |||||||
|      * Refresh the data. |      * Refresh the data. | ||||||
|      * |      * | ||||||
|      * @param refresher Refresher. |      * @param refresher Refresher. | ||||||
|      * @param done Function to call when done. |  | ||||||
|      * @return Promise resolved when done. |      * @return Promise resolved when done. | ||||||
|      */ |      */ | ||||||
|     async doRefresh(refresher?: IonRefresher | null, done?: () => void): Promise<void> { |     async doRefresh(refresher?: IonRefresher | null): Promise<void> { | ||||||
|         if (this.content) { |  | ||||||
|             this.refreshIcon = CoreConstants.ICON_LOADING; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         try { |         try { | ||||||
|             await this.content?.refreshContent(false); |             await this.content?.refreshContent(false); | ||||||
|         } finally { |         } finally { | ||||||
|             refresher?.complete(); |             refresher?.complete(); | ||||||
|             done && done(); |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Function called when the data of the site plugin content is loaded. |      * Function called when the data of the site plugin content is loaded. | ||||||
|      */ |      */ | ||||||
|  |     // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | ||||||
|     contentLoaded(refresh: boolean): void { |     contentLoaded(refresh: boolean): void { | ||||||
|         this.refreshIcon = CoreConstants.ICON_REFRESH; |         return; | ||||||
| 
 |  | ||||||
|         // Check if there is a prefetch handler for this type of module.
 |  | ||||||
|         if (CoreCourseModulePrefetchDelegate.getPrefetchHandlerFor(this.module.modname)) { |  | ||||||
|             CoreCourseHelper.fillContextMenu(this, this.module, this.courseId, refresh, this.component); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Function called when starting to load the data of the site plugin content. |      * Function called when starting to load the data of the site plugin content. | ||||||
|      */ |      */ | ||||||
|     contentLoading(): void { |     contentLoading(): void { | ||||||
|         this.refreshIcon = CoreConstants.ICON_LOADING; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Expand the description. |      * Expand the description. | ||||||
|  |      * | ||||||
|  |      * @deprecated since 4.0 | ||||||
|      */ |      */ | ||||||
|     expandDescription(): void { |     expandDescription(): void { | ||||||
|         if (!this.description) { |         this.openModuleSummary(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Opens a module summary page. | ||||||
|  |      */ | ||||||
|  |     async openModuleSummary(): Promise<void> { | ||||||
|  |         if (!this.module) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         CoreTextUtils.viewText(Translate.instant('core.description'), this.description, { |         const data = await CoreDomUtils.openSideModal<CoreCourseModuleSummaryResult>({ | ||||||
|             component: this.component, |             component: CoreCourseModuleSummaryComponent, | ||||||
|             componentId: this.module.id, |             componentProps: { | ||||||
|             filter: true, |                 moduleId: this.module.id, | ||||||
|             contextLevel: 'module', |                 module: this.module, | ||||||
|             instanceId: this.module.id, |                 description: this.description, | ||||||
|             courseId: this.courseId, |                 component: this.component, | ||||||
|  |                 courseId: this.courseId, | ||||||
|  |                 displayOptions: { | ||||||
|  |                     displayOpenInBrowser: this.displayOpenInBrowser, | ||||||
|  |                     displayDescription: this.displayDescription, | ||||||
|  |                     displayRefresh: this.displayRefresh, | ||||||
|  |                     displayPrefetch: this.displayPrefetch, | ||||||
|  |                     displaySize: this.displaySize, | ||||||
|  |                     displayBlog: false, | ||||||
|  |                 }, | ||||||
|  |             }, | ||||||
|         }); |         }); | ||||||
|  | 
 | ||||||
|  |         if (data && data.action == 'refresh') { | ||||||
|  |             const modal = await CoreDomUtils.showModalLoading(); | ||||||
|  | 
 | ||||||
|  |             try { | ||||||
|  |                 await this.doRefresh(); | ||||||
|  |             } finally { | ||||||
|  |                 modal.dismiss(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Prefetch the module. |      * Prefetch the module. | ||||||
|  |      * | ||||||
|  |      * @deprecated since 4.0 | ||||||
|      */ |      */ | ||||||
|     prefetch(): void { |     async prefetch(): Promise<void> { | ||||||
|         CoreCourseHelper.contextMenuPrefetch(this, this.module, this.courseId); |         try { | ||||||
|  |             // We need to call getDownloadSize, the package might have been updated.
 | ||||||
|  |             const size = await CoreCourseModulePrefetchDelegate.getModuleDownloadSize(this.module, this.courseId, true); | ||||||
|  | 
 | ||||||
|  |             await CoreDomUtils.confirmDownloadSize(size); | ||||||
|  | 
 | ||||||
|  |             await CoreCourseModulePrefetchDelegate.prefetchModule(this.module, this.courseId, true); | ||||||
|  |         } catch (error) { | ||||||
|  |             if (!this.isDestroyed) { | ||||||
|  |                 CoreDomUtils.showErrorModalDefault(error, 'core.errordownloading', true); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Confirm and remove downloaded files. |      * Confirm and remove downloaded files. | ||||||
|  |      * | ||||||
|  |      * @deprecated since 4.0 | ||||||
|      */ |      */ | ||||||
|     removeFiles(): void { |     async removeFiles(): Promise<void> { | ||||||
|         CoreCourseHelper.confirmAndRemoveFiles(this.module, this.courseId); |         let modal: CoreIonLoadingElement | undefined; | ||||||
|  | 
 | ||||||
|  |         try { | ||||||
|  |             await CoreDomUtils.showDeleteConfirm('addon.storagemanager.confirmdeletedatafrom', { name: this.module.name }); | ||||||
|  | 
 | ||||||
|  |             modal = await CoreDomUtils.showModalLoading(); | ||||||
|  | 
 | ||||||
|  |             await CoreCourseHelper.removeModuleStoredData(this.module, this.courseId); | ||||||
|  |         } catch (error) { | ||||||
|  |             if (error) { | ||||||
|  |                 CoreDomUtils.showErrorModal(error); | ||||||
|  |             } | ||||||
|  |         } finally { | ||||||
|  |             modal?.dismiss(); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user