forked from EVOgeek/Vmeda.Online
		
	
						commit
						337b92aed6
					
				@ -126,7 +126,7 @@ const appConfig = {
 | 
				
			|||||||
                ignoreParameters: true,
 | 
					                ignoreParameters: true,
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
        '@typescript-eslint/no-non-null-assertion': 'off',
 | 
					        '@typescript-eslint/no-non-null-assertion': 'warn',
 | 
				
			||||||
        '@typescript-eslint/no-redeclare': 'error',
 | 
					        '@typescript-eslint/no-redeclare': 'error',
 | 
				
			||||||
        '@typescript-eslint/no-this-alias': 'error',
 | 
					        '@typescript-eslint/no-this-alias': 'error',
 | 
				
			||||||
        '@typescript-eslint/no-unused-vars': 'error',
 | 
					        '@typescript-eslint/no-unused-vars': 'error',
 | 
				
			||||||
 | 
				
			|||||||
@ -133,8 +133,11 @@ export class AddonModBookIndexComponent extends CoreCourseModuleMainResourceComp
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            await this.loadBookData();
 | 
					            await this.loadBookData();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.contentsMap = AddonModBook.getContentsMap(this.module.contents);
 | 
					            // Get contents. No need to refresh, it has been done in downloadResourceIfNeeded.
 | 
				
			||||||
            this.chapters = AddonModBook.getTocList(this.module.contents);
 | 
					            const contents = await CoreCourse.getModuleContents(this.module, this.courseId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.contentsMap = AddonModBook.getContentsMap(contents);
 | 
				
			||||||
 | 
					            this.chapters = AddonModBook.getTocList(contents);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (typeof this.currentChapter == 'undefined' && typeof this.initialChapterId != 'undefined' && this.chapters) {
 | 
					            if (typeof this.currentChapter == 'undefined' && typeof this.initialChapterId != 'undefined' && this.chapters) {
 | 
				
			||||||
                // Initial chapter set. Validate that the chapter exists.
 | 
					                // Initial chapter set. Validate that the chapter exists.
 | 
				
			||||||
 | 
				
			|||||||
@ -34,8 +34,8 @@
 | 
				
			|||||||
        contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
 | 
					        contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
 | 
				
			||||||
    </core-course-module-description>
 | 
					    </core-course-module-description>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <ion-list *ngIf="contents && (contents!.files.length + contents!.folders.length > 0)">
 | 
					    <ion-list *ngIf="contents && (contents.files.length + contents.folders.length > 0)">
 | 
				
			||||||
        <ng-container *ngFor="let folder of contents!.folders">
 | 
					        <ng-container *ngFor="let folder of contents.folders">
 | 
				
			||||||
            <ion-item class="item-file" (click)="openFolder(folder)" detail="true" button>
 | 
					            <ion-item class="item-file" (click)="openFolder(folder)" detail="true" button>
 | 
				
			||||||
                <ion-icon name="fas-folder" slot="start" [attr.aria-label]="'core.folder' | translate"></ion-icon>
 | 
					                <ion-icon name="fas-folder" slot="start" [attr.aria-label]="'core.folder' | translate"></ion-icon>
 | 
				
			||||||
                <ion-label>
 | 
					                <ion-label>
 | 
				
			||||||
@ -43,12 +43,12 @@
 | 
				
			|||||||
                </ion-label>
 | 
					                </ion-label>
 | 
				
			||||||
            </ion-item>
 | 
					            </ion-item>
 | 
				
			||||||
        </ng-container>
 | 
					        </ng-container>
 | 
				
			||||||
        <ng-container *ngFor="let file of contents!.files">
 | 
					        <ng-container *ngFor="let file of contents.files">
 | 
				
			||||||
            <core-file [file]="file" [component]="component" [componentId]="componentId"></core-file>
 | 
					            <core-file [file]="file" [component]="component" [componentId]="componentId"></core-file>
 | 
				
			||||||
        </ng-container>
 | 
					        </ng-container>
 | 
				
			||||||
    </ion-list>
 | 
					    </ion-list>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <core-empty-box *ngIf="!contents || (contents!.files.length + contents!.folders.length == 0)" icon="far-folder-open"
 | 
					    <core-empty-box *ngIf="!contents || (contents.files.length + contents.folders.length == 0)" icon="far-folder-open"
 | 
				
			||||||
        [message]=" 'addon.mod_folder.emptyfilelist' | translate"></core-empty-box>
 | 
					        [message]=" 'addon.mod_folder.emptyfilelist' | translate"></core-empty-box>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</core-loading>
 | 
					</core-loading>
 | 
				
			||||||
 | 
				
			|||||||
@ -95,12 +95,13 @@ export class AddonModFolderIndexComponent extends CoreCourseModuleMainResourceCo
 | 
				
			|||||||
    protected async fetchContent(refresh = false): Promise<void> {
 | 
					    protected async fetchContent(refresh = false): Promise<void> {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            this.folderInstance = await AddonModFolder.getFolder(this.courseId, this.module.id);
 | 
					            this.folderInstance = await AddonModFolder.getFolder(this.courseId, this.module.id);
 | 
				
			||||||
            await CoreCourse.loadModuleContents(this.module, this.courseId, undefined, false, refresh);
 | 
					
 | 
				
			||||||
 | 
					            const contents = await CoreCourse.getModuleContents(this.module, this.courseId, undefined, false, refresh);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.dataRetrieved.emit(this.folderInstance || this.module);
 | 
					            this.dataRetrieved.emit(this.folderInstance || this.module);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.description = this.folderInstance ? this.folderInstance.intro : this.module.description;
 | 
					            this.description = this.folderInstance ? this.folderInstance.intro : this.module.description;
 | 
				
			||||||
            this.contents = AddonModFolderHelper.formatContents(this.module.contents);
 | 
					            this.contents = AddonModFolderHelper.formatContents(contents);
 | 
				
			||||||
        } finally {
 | 
					        } finally {
 | 
				
			||||||
            this.fillContextMenu(refresh);
 | 
					            this.fillContextMenu(refresh);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -85,7 +85,10 @@ export class AddonModImscpIndexComponent extends CoreCourseModuleMainResourceCom
 | 
				
			|||||||
            this.description = imscp.intro;
 | 
					            this.description = imscp.intro;
 | 
				
			||||||
            this.dataRetrieved.emit(imscp);
 | 
					            this.dataRetrieved.emit(imscp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.items = AddonModImscp.createItemList(this.module.contents);
 | 
					            // 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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (this.items.length && typeof this.currentItem == 'undefined') {
 | 
					            if (this.items.length && typeof this.currentItem == 'undefined') {
 | 
				
			||||||
                this.currentItem = this.items[0].href;
 | 
					                this.currentItem = this.items[0].href;
 | 
				
			||||||
 | 
				
			|||||||
@ -229,8 +229,10 @@ export class AddonModImscpProvider {
 | 
				
			|||||||
     * @return Promise resolved with the item src.
 | 
					     * @return Promise resolved with the item src.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    async getIframeSrc(module: CoreCourseModule, itemHref?: string): Promise<string> {
 | 
					    async getIframeSrc(module: CoreCourseModule, itemHref?: string): Promise<string> {
 | 
				
			||||||
 | 
					        const contents = await CoreCourse.getModuleContents(module);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!itemHref) {
 | 
					        if (!itemHref) {
 | 
				
			||||||
            const toc = this.getToc(module.contents);
 | 
					            const toc = this.getToc(contents);
 | 
				
			||||||
            if (!toc.length) {
 | 
					            if (!toc.length) {
 | 
				
			||||||
                throw new CoreError('Empty TOC');
 | 
					                throw new CoreError('Empty TOC');
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -246,7 +248,7 @@ export class AddonModImscpProvider {
 | 
				
			|||||||
        } catch (error) {
 | 
					        } catch (error) {
 | 
				
			||||||
            // Error getting directory, there was an error downloading or we're in browser. Return online URL if connected.
 | 
					            // Error getting directory, there was an error downloading or we're in browser. Return online URL if connected.
 | 
				
			||||||
            if (CoreApp.isOnline()) {
 | 
					            if (CoreApp.isOnline()) {
 | 
				
			||||||
                const indexUrl = this.getFileUrlFromContents(module.contents, itemHref);
 | 
					                const indexUrl = this.getFileUrlFromContents(contents, itemHref);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (indexUrl) {
 | 
					                if (indexUrl) {
 | 
				
			||||||
                    const site = await CoreSites.getSite(siteId);
 | 
					                    const site = await CoreSites.getSite(siteId);
 | 
				
			||||||
 | 
				
			|||||||
@ -81,9 +81,12 @@ export class AddonModPageIndexComponent extends CoreCourseModuleMainResourceComp
 | 
				
			|||||||
            // Download the resource if it needs to be downloaded.
 | 
					            // Download the resource if it needs to be downloaded.
 | 
				
			||||||
            const downloadResult = await this.downloadResourceIfNeeded(refresh);
 | 
					            const downloadResult = await this.downloadResourceIfNeeded(refresh);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Get contents. No need to refresh, it has been done in downloadResourceIfNeeded.
 | 
				
			||||||
 | 
					            const contents = await CoreCourse.getModuleContents(this.module, this.courseId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            const results = await Promise.all([
 | 
					            const results = await Promise.all([
 | 
				
			||||||
                this.loadPageData(),
 | 
					                this.loadPageData(),
 | 
				
			||||||
                AddonModPageHelper.getPageHtml(this.module.contents, this.module.id),
 | 
					                AddonModPageHelper.getPageHtml(contents, this.module.id),
 | 
				
			||||||
            ]);
 | 
					            ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.contents = results[1];
 | 
					            this.contents = results[1];
 | 
				
			||||||
 | 
				
			|||||||
@ -101,9 +101,9 @@ export class AddonModResourceIndexComponent extends CoreCourseModuleMainResource
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    protected async fetchContent(refresh?: boolean): Promise<void> {
 | 
					    protected async fetchContent(refresh?: boolean): Promise<void> {
 | 
				
			||||||
        // Load module contents if needed. Passing refresh is needed to force reloading contents.
 | 
					        // Load module contents if needed. Passing refresh is needed to force reloading contents.
 | 
				
			||||||
        await CoreCourse.loadModuleContents(this.module, this.courseId, undefined, false, refresh);
 | 
					        const contents = await CoreCourse.getModuleContents(this.module, this.courseId, undefined, false, refresh);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!this.module.contents || !this.module.contents.length) {
 | 
					        if (!contents.length) {
 | 
				
			||||||
            throw new CoreError(Translate.instant('core.filenotfound'));
 | 
					            throw new CoreError(Translate.instant('core.filenotfound'));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -155,10 +155,10 @@ export class AddonModResourceIndexComponent extends CoreCourseModuleMainResource
 | 
				
			|||||||
                this.warning = '';
 | 
					                this.warning = '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (this.isIOS) {
 | 
					                if (this.isIOS) {
 | 
				
			||||||
                    this.shouldOpenInBrowser = CoreFileHelper.shouldOpenInBrowser(this.module.contents[0]);
 | 
					                    this.shouldOpenInBrowser = CoreFileHelper.shouldOpenInBrowser(contents[0]);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                const mimetype = await CoreUtils.getMimeTypeFromUrl(CoreFileHelper.getFileUrl(this.module.contents[0]));
 | 
					                const mimetype = await CoreUtils.getMimeTypeFromUrl(CoreFileHelper.getFileUrl(contents[0]));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                this.isStreamedFile = CoreMimetypeUtils.isStreamedMimetype(mimetype);
 | 
					                this.isStreamedFile = CoreMimetypeUtils.isStreamedMimetype(mimetype);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
				
			|||||||
@ -26,7 +26,7 @@ import { CoreDomUtils } from '@services/utils/dom';
 | 
				
			|||||||
import { CoreMimetypeUtils } from '@services/utils/mimetype';
 | 
					import { CoreMimetypeUtils } from '@services/utils/mimetype';
 | 
				
			||||||
import { CoreTextUtils } from '@services/utils/text';
 | 
					import { CoreTextUtils } from '@services/utils/text';
 | 
				
			||||||
import { CoreUtilsOpenFileOptions } from '@services/utils/utils';
 | 
					import { CoreUtilsOpenFileOptions } from '@services/utils/utils';
 | 
				
			||||||
import { makeSingleton } from '@singletons';
 | 
					import { makeSingleton, Translate } from '@singletons';
 | 
				
			||||||
import { AddonModResource, AddonModResourceProvider } from './resource';
 | 
					import { AddonModResource, AddonModResourceProvider } from './resource';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@ -43,15 +43,17 @@ export class AddonModResourceHelperProvider {
 | 
				
			|||||||
     * @return Promise resolved with the HTML.
 | 
					     * @return Promise resolved with the HTML.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    async getEmbeddedHtml(module: CoreCourseWSModule, courseId: number): Promise<string> {
 | 
					    async getEmbeddedHtml(module: CoreCourseWSModule, courseId: number): Promise<string> {
 | 
				
			||||||
 | 
					        const contents = await CoreCourse.getModuleContents(module, courseId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const result = await CoreCourseHelper.downloadModuleWithMainFileIfNeeded(
 | 
					        const result = await CoreCourseHelper.downloadModuleWithMainFileIfNeeded(
 | 
				
			||||||
            module,
 | 
					            module,
 | 
				
			||||||
            courseId,
 | 
					            courseId,
 | 
				
			||||||
            AddonModResourceProvider.COMPONENT,
 | 
					            AddonModResourceProvider.COMPONENT,
 | 
				
			||||||
            module.id,
 | 
					            module.id,
 | 
				
			||||||
            module.contents,
 | 
					            contents,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return CoreMimetypeUtils.getEmbeddedHtml(module.contents[0], result.path);
 | 
					        return CoreMimetypeUtils.getEmbeddedHtml(contents[0], result.path);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@ -61,7 +63,7 @@ export class AddonModResourceHelperProvider {
 | 
				
			|||||||
     * @return Promise resolved with the iframe src.
 | 
					     * @return Promise resolved with the iframe src.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    async getIframeSrc(module: CoreCourseWSModule): Promise<string> {
 | 
					    async getIframeSrc(module: CoreCourseWSModule): Promise<string> {
 | 
				
			||||||
        if (!module.contents.length) {
 | 
					        if (!module.contents?.length) {
 | 
				
			||||||
            throw new CoreError('No contents available in module');
 | 
					            throw new CoreError('No contents available in module');
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -98,15 +100,19 @@ export class AddonModResourceHelperProvider {
 | 
				
			|||||||
    isDisplayedEmbedded(module: CoreCourseWSModule, display: number): boolean {
 | 
					    isDisplayedEmbedded(module: CoreCourseWSModule, display: number): boolean {
 | 
				
			||||||
        const currentSite = CoreSites.getCurrentSite();
 | 
					        const currentSite = CoreSites.getCurrentSite();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if ((!module.contents.length && !module.contentsinfo) ||
 | 
					        if (!CoreFile.isAvailable() ||
 | 
				
			||||||
            !CoreFile.isAvailable() ||
 | 
					                (currentSite && !currentSite.isVersionGreaterEqualThan('3.7') && this.isNextcloudFile(module))) {
 | 
				
			||||||
            (currentSite && !currentSite.isVersionGreaterEqualThan('3.7') && this.isNextcloudFile(module))) {
 | 
					 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const ext = module.contentsinfo
 | 
					        let ext: string | undefined;
 | 
				
			||||||
            ? CoreMimetypeUtils.getExtension(module.contentsinfo.mimetypes[0])
 | 
					        if (module.contentsinfo) {
 | 
				
			||||||
            : CoreMimetypeUtils.getFileExtension(module.contents[0].filename);
 | 
					            ext = CoreMimetypeUtils.getExtension(module.contentsinfo.mimetypes[0]);
 | 
				
			||||||
 | 
					        } else if (module.contents?.length) {
 | 
				
			||||||
 | 
					            ext = CoreMimetypeUtils.getFileExtension(module.contents[0].filename);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return (display == CoreConstants.RESOURCELIB_DISPLAY_EMBED || display == CoreConstants.RESOURCELIB_DISPLAY_AUTO) &&
 | 
					        return (display == CoreConstants.RESOURCELIB_DISPLAY_EMBED || display == CoreConstants.RESOURCELIB_DISPLAY_AUTO) &&
 | 
				
			||||||
            CoreMimetypeUtils.canBeEmbedded(ext);
 | 
					            CoreMimetypeUtils.canBeEmbedded(ext);
 | 
				
			||||||
@ -144,10 +150,15 @@ export class AddonModResourceHelperProvider {
 | 
				
			|||||||
     * @param siteId Site ID. If not defined, current site.
 | 
					     * @param siteId Site ID. If not defined, current site.
 | 
				
			||||||
     * @return Promise resolved with boolean: whether main file is downloadable.
 | 
					     * @return Promise resolved with boolean: whether main file is downloadable.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    isMainFileDownloadable(module: CoreCourseWSModule, siteId?: string): Promise<boolean> {
 | 
					    async isMainFileDownloadable(module: CoreCourseWSModule, siteId?: string): Promise<boolean> {
 | 
				
			||||||
 | 
					        const contents = await CoreCourse.getModuleContents(module);
 | 
				
			||||||
 | 
					        if (!contents.length) {
 | 
				
			||||||
 | 
					            throw new CoreError(Translate.instant('core.filenotfound'));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        siteId = siteId || CoreSites.getCurrentSiteId();
 | 
					        siteId = siteId || CoreSites.getCurrentSiteId();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const mainFile = module.contents[0];
 | 
					        const mainFile = contents[0];
 | 
				
			||||||
        const timemodified = CoreFileHelper.getFileTimemodified(mainFile);
 | 
					        const timemodified = CoreFileHelper.getFileTimemodified(mainFile);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return CoreFilepool.isFileDownloadable(siteId, mainFile.fileurl, timemodified);
 | 
					        return CoreFilepool.isFileDownloadable(siteId, mainFile.fileurl, timemodified);
 | 
				
			||||||
 | 
				
			|||||||
@ -95,11 +95,19 @@ export class AddonModUrlIndexComponent extends CoreCourseModuleMainResourceCompo
 | 
				
			|||||||
                this.displayDescription = typeof unserialized.printintro == 'undefined' || !!unserialized.printintro;
 | 
					                this.displayDescription = typeof unserialized.printintro == 'undefined' || !!unserialized.printintro;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Try to load module contents, it's needed to get the URL with parameters.
 | 
					            // Try to get module contents, it's needed to get the URL with parameters.
 | 
				
			||||||
            await CoreCourse.loadModuleContents(this.module, this.courseId, undefined, false, refresh, undefined, 'url');
 | 
					            const contents = await CoreCourse.getModuleContents(
 | 
				
			||||||
 | 
					                this.module,
 | 
				
			||||||
 | 
					                this.courseId,
 | 
				
			||||||
 | 
					                undefined,
 | 
				
			||||||
 | 
					                false,
 | 
				
			||||||
 | 
					                refresh,
 | 
				
			||||||
 | 
					                undefined,
 | 
				
			||||||
 | 
					                'url',
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Always use the URL from the module because it already includes the parameters.
 | 
					            // Always use the URL from the module because it already includes the parameters.
 | 
				
			||||||
            this.url = this.module.contents[0] && this.module.contents[0].fileurl ? this.module.contents[0].fileurl : undefined;
 | 
					            this.url = contents[0] && contents[0].fileurl ? contents[0].fileurl : undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            await this.calculateDisplayOptions(url);
 | 
					            await this.calculateDisplayOptions(url);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -112,12 +120,12 @@ export class AddonModUrlIndexComponent extends CoreCourseModuleMainResourceCompo
 | 
				
			|||||||
            this.description = mod.description;
 | 
					            this.description = mod.description;
 | 
				
			||||||
            this.dataRetrieved.emit(mod);
 | 
					            this.dataRetrieved.emit(mod);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (!mod.contents.length) {
 | 
					            if (!mod.contents?.length) {
 | 
				
			||||||
                // If the data was cached maybe we don't have contents. Reject.
 | 
					                // If the data was cached maybe we don't have contents. Reject.
 | 
				
			||||||
                throw new CoreError('No contents found in module.');
 | 
					                throw new CoreError('No contents found in module.');
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.url = mod.contents && mod.contents[0] && mod.contents[0].fileurl ? mod.contents[0].fileurl : undefined;
 | 
					            this.url = mod.contents[0].fileurl ? mod.contents[0].fileurl : undefined;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -77,7 +77,8 @@ export class AddonModUrlModuleHandlerService implements CoreCourseModuleHandler
 | 
				
			|||||||
                // Ignore errors.
 | 
					                // Ignore errors.
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            AddonModUrlHelper.open(module.contents[0].fileurl);
 | 
					            const contents = await CoreCourse.getModuleContents(module, courseId);
 | 
				
			||||||
 | 
					            AddonModUrlHelper.open(contents[0].fileurl);
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const handlerData: CoreCourseModuleHandlerData = {
 | 
					        const handlerData: CoreCourseModuleHandlerData = {
 | 
				
			||||||
@ -141,9 +142,9 @@ export class AddonModUrlModuleHandlerService implements CoreCourseModuleHandler
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    protected async hideLinkButton(module: CoreCourseAnyModuleData, courseId: number): Promise<boolean> {
 | 
					    protected async hideLinkButton(module: CoreCourseAnyModuleData, courseId: number): Promise<boolean> {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            await CoreCourse.loadModuleContents(module, courseId, undefined, false, false, undefined, this.modName);
 | 
					            const contents = await CoreCourse.getModuleContents(module, courseId, undefined, false, false, undefined, this.modName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return !(module.contents && module.contents[0] && module.contents[0].fileurl);
 | 
					            return !(contents[0] && contents[0].fileurl);
 | 
				
			||||||
        } catch {
 | 
					        } catch {
 | 
				
			||||||
            // Module contents could not be loaded, most probably device is offline.
 | 
					            // Module contents could not be loaded, most probably device is offline.
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
@ -166,11 +167,10 @@ export class AddonModUrlModuleHandlerService implements CoreCourseModuleHandler
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    protected async shouldOpenLink(module: CoreCourseModule, courseId: number): Promise<boolean> {
 | 
					    protected async shouldOpenLink(module: CoreCourseModule, courseId: number): Promise<boolean> {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            // First of all, make sure module contents are loaded.
 | 
					            const contents = await CoreCourse.getModuleContents(module, courseId, undefined, false, false, undefined, this.modName);
 | 
				
			||||||
            await CoreCourse.loadModuleContents(module, courseId, undefined, false, false, undefined, this.modName);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Check if the URL can be handled by the app. If so, always open it directly.
 | 
					            // Check if the URL can be handled by the app. If so, always open it directly.
 | 
				
			||||||
            const canHandle = await CoreContentLinksHelper.canHandleLink(module.contents[0].fileurl, courseId, undefined, true);
 | 
					            const canHandle = await CoreContentLinksHelper.canHandleLink(contents[0].fileurl, courseId, undefined, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (canHandle) {
 | 
					            if (canHandle) {
 | 
				
			||||||
                // URL handled by the app, open it directly.
 | 
					                // URL handled by the app, open it directly.
 | 
				
			||||||
 | 
				
			|||||||
@ -100,6 +100,9 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy,
 | 
				
			|||||||
        this.showCompletion = !!CoreSites.getCurrentSite()?.isVersionGreaterEqualThan('3.11');
 | 
					        this.showCompletion = !!CoreSites.getCurrentSite()?.isVersionGreaterEqualThan('3.11');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (this.showCompletion) {
 | 
					        if (this.showCompletion) {
 | 
				
			||||||
 | 
					            CoreCourseHelper.calculateModuleCompletionData(this.module, this.courseId);
 | 
				
			||||||
 | 
					            CoreCourseHelper.loadModuleOfflineCompletion(this.courseId, this.module);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            this.completionObserver = CoreEvents.on(CoreEvents.COMPLETION_MODULE_VIEWED, async (data) => {
 | 
					            this.completionObserver = CoreEvents.on(CoreEvents.COMPLETION_MODULE_VIEWED, async (data) => {
 | 
				
			||||||
                if (data && data.cmId == this.module.id) {
 | 
					                if (data && data.cmId == this.module.id) {
 | 
				
			||||||
                    await CoreCourse.invalidateModule(this.module.id);
 | 
					                    await CoreCourse.invalidateModule(this.module.id);
 | 
				
			||||||
@ -387,7 +390,7 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy,
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!this.module.contents.length || (refresh && !contentsAlreadyLoaded)) {
 | 
					        if (!this.module.contents?.length || (refresh && !contentsAlreadyLoaded)) {
 | 
				
			||||||
            // Try to load the contents.
 | 
					            // Try to load the contents.
 | 
				
			||||||
            const ignoreCache = refresh && CoreApp.isOnline();
 | 
					            const ignoreCache = refresh && CoreApp.isOnline();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -730,13 +730,11 @@ export class CoreCourseHelperProvider {
 | 
				
			|||||||
        siteId = siteId || CoreSites.getCurrentSiteId();
 | 
					        siteId = siteId || CoreSites.getCurrentSiteId();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!files || !files.length) {
 | 
					        if (!files || !files.length) {
 | 
				
			||||||
            // Make sure that module contents are loaded.
 | 
					            // Try to use module contents.
 | 
				
			||||||
            await CoreCourse.loadModuleContents(module, courseId);
 | 
					            files = await CoreCourse.getModuleContents(module, courseId);
 | 
				
			||||||
 | 
					 | 
				
			||||||
            files = module.contents;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!files || !files.length) {
 | 
					        if (!files.length) {
 | 
				
			||||||
            throw new CoreError(Translate.instant('core.filenotfound'));
 | 
					            throw new CoreError(Translate.instant('core.filenotfound'));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1033,7 +1031,7 @@ export class CoreCourseHelperProvider {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // There's no prefetch handler for the module, just download the files.
 | 
					        // There's no prefetch handler for the module, just download the files.
 | 
				
			||||||
        files = files || module.contents;
 | 
					        files = files || module.contents || [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await CoreFilepool.downloadOrPrefetchFiles(siteId, files, false, false, component, componentId);
 | 
					        await CoreFilepool.downloadOrPrefetchFiles(siteId, files, false, false, component, componentId);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -885,9 +885,47 @@ export class CoreCourseProvider {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const mod = await this.getModule(module.id, courseId, sectionId, preferCache, ignoreCache, siteId, modName);
 | 
					        const mod = await this.getModule(module.id, courseId, sectionId, preferCache, ignoreCache, siteId, modName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!mod.contents) {
 | 
				
			||||||
 | 
					            throw new CoreError(Translate.instant('core.course.modulenotfound'));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        module.contents = mod.contents;
 | 
					        module.contents = mod.contents;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get module contents. If not present, this function will try to load them into module.contents.
 | 
				
			||||||
 | 
					     * It will throw an error if contents cannot be loaded.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param module Module to get its contents.
 | 
				
			||||||
 | 
					     * @param courseId The course ID. Recommended to speed up the process and minimize data usage.
 | 
				
			||||||
 | 
					     * @param sectionId The section ID.
 | 
				
			||||||
 | 
					     * @param preferCache True if shouldn't call WS if data is cached, false otherwise.
 | 
				
			||||||
 | 
					     * @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
 | 
				
			||||||
 | 
					     * @param siteId Site ID. If not defined, current site.
 | 
				
			||||||
 | 
					     * @param modName If set, the app will retrieve all modules of this type with a single WS call. This reduces the
 | 
				
			||||||
 | 
					     *                number of WS calls, but it isn't recommended for modules that can return a lot of contents.
 | 
				
			||||||
 | 
					     * @return Promise resolved when loaded.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    async getModuleContents(
 | 
				
			||||||
 | 
					        module: CoreCourseAnyModuleData,
 | 
				
			||||||
 | 
					        courseId?: number,
 | 
				
			||||||
 | 
					        sectionId?: number,
 | 
				
			||||||
 | 
					        preferCache?: boolean,
 | 
				
			||||||
 | 
					        ignoreCache?: boolean,
 | 
				
			||||||
 | 
					        siteId?: string,
 | 
				
			||||||
 | 
					        modName?: string,
 | 
				
			||||||
 | 
					    ): Promise<CoreCourseModuleContentFile[]> {
 | 
				
			||||||
 | 
					        // Make sure contents are loaded.
 | 
				
			||||||
 | 
					        await this.loadModuleContents(module, courseId, sectionId, preferCache, ignoreCache, siteId, modName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!module.contents) {
 | 
				
			||||||
 | 
					            throw new CoreError(Translate.instant('core.course.modulenotfound'));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return module.contents;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Report a course and section as being viewed.
 | 
					     * Report a course and section as being viewed.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
@ -1450,7 +1488,7 @@ export type CoreCourseWSModule = {
 | 
				
			|||||||
    noviewlink?: boolean; // Whether the module has no view page.
 | 
					    noviewlink?: boolean; // Whether the module has no view page.
 | 
				
			||||||
    completion?: number; // Type of completion tracking: 0 means none, 1 manual, 2 automatic.
 | 
					    completion?: number; // Type of completion tracking: 0 means none, 1 manual, 2 automatic.
 | 
				
			||||||
    completiondata?: CoreCourseModuleWSCompletionData; // Module completion data.
 | 
					    completiondata?: CoreCourseModuleWSCompletionData; // Module completion data.
 | 
				
			||||||
    contents: CoreCourseModuleContentFile[];
 | 
					    contents?: CoreCourseModuleContentFile[];
 | 
				
			||||||
    dates?: {
 | 
					    dates?: {
 | 
				
			||||||
        label: string;
 | 
					        label: string;
 | 
				
			||||||
        timestamp: number;
 | 
					        timestamp: number;
 | 
				
			||||||
@ -1589,5 +1627,5 @@ type CoreCompletionUpdateActivityCompletionStatusManuallyWSParams = {
 | 
				
			|||||||
 * Any of the possible module WS data.
 | 
					 * Any of the possible module WS data.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
export type CoreCourseAnyModuleData = CoreCourseWSModule | CoreCourseModuleBasicInfo & {
 | 
					export type CoreCourseAnyModuleData = CoreCourseWSModule | CoreCourseModuleBasicInfo & {
 | 
				
			||||||
    contents?: CoreCourseModuleContentFile[]; // Calculated in the app in loadModuleContents.
 | 
					    contents?: CoreCourseModuleContentFile[]; // If needed, calculated in the app in loadModuleContents.
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user