forked from CIT/Vmeda.Online
		
	Merge pull request #2694 from crazyserver/MOBILE-3646
MOBILE-3646 imscp Add imscp activity module
This commit is contained in:
		
						commit
						fd314eb4d8
					
				@ -15,7 +15,7 @@
 | 
				
			|||||||
    <nav>
 | 
					    <nav>
 | 
				
			||||||
        <ion-list>
 | 
					        <ion-list>
 | 
				
			||||||
            <ion-item class="ion-text-wrap" *ngFor="let chapter of chapters" (click)="loadChapter(chapter.id)"
 | 
					            <ion-item class="ion-text-wrap" *ngFor="let chapter of chapters" (click)="loadChapter(chapter.id)"
 | 
				
			||||||
                [class.core-nav-item-selected]="selected == chapter.id"
 | 
					                [class.core-selected-item]="selected == chapter.id"
 | 
				
			||||||
                [class.item-dimmed]="chapter.hidden">
 | 
					                [class.item-dimmed]="chapter.hidden">
 | 
				
			||||||
                <ion-label>
 | 
					                <ion-label>
 | 
				
			||||||
                    <p [class.ion-padding-left]="addPadding && chapter.level == 1 ? true : null">
 | 
					                    <p [class.ion-padding-left]="addPadding && chapter.level == 1 ? true : null">
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										37
									
								
								src/addons/mod/imscp/components/components.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/addons/mod/imscp/components/components.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					// (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 { CoreSharedModule } from '@/core/shared.module';
 | 
				
			||||||
 | 
					import { CoreCourseComponentsModule } from '@features/course/components/components.module';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { AddonModImscpIndexComponent } from './index';
 | 
				
			||||||
 | 
					import { AddonModImscpTocComponent } from './toc/toc';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@NgModule({
 | 
				
			||||||
 | 
					    declarations: [
 | 
				
			||||||
 | 
					        AddonModImscpIndexComponent,
 | 
				
			||||||
 | 
					        AddonModImscpTocComponent,
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    imports: [
 | 
				
			||||||
 | 
					        CoreSharedModule,
 | 
				
			||||||
 | 
					        CoreCourseComponentsModule,
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    exports: [
 | 
				
			||||||
 | 
					        AddonModImscpIndexComponent,
 | 
				
			||||||
 | 
					        AddonModImscpTocComponent,
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class AddonModImscpComponentsModule {}
 | 
				
			||||||
@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					<!-- Buttons to add to the header. -->
 | 
				
			||||||
 | 
					<core-navbar-buttons slot="end">
 | 
				
			||||||
 | 
					    <ion-button (click)="showToc()">
 | 
				
			||||||
 | 
					        <ion-icon name="fas-bookmark" slot="icon-only"></ion-icon>
 | 
				
			||||||
 | 
					    </ion-button>
 | 
				
			||||||
 | 
					    <core-context-menu>
 | 
				
			||||||
 | 
					        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate"
 | 
				
			||||||
 | 
					            [href]="externalUrl" iconAction="fas-external-link-alt">
 | 
				
			||||||
 | 
					        </core-context-menu-item>
 | 
				
			||||||
 | 
					        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate"
 | 
				
			||||||
 | 
					            (action)="expandDescription()" iconAction="fas-arrow-right">
 | 
				
			||||||
 | 
					        </core-context-menu-item>
 | 
				
			||||||
 | 
					        <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}"
 | 
				
			||||||
 | 
					            iconAction="far-newspaper" (action)="gotoBlog()">
 | 
				
			||||||
 | 
					        </core-context-menu-item>
 | 
				
			||||||
 | 
					        <core-context-menu-item [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)"
 | 
				
			||||||
 | 
					            [iconAction]="refreshIcon" [closeOnClick]="false">
 | 
				
			||||||
 | 
					        </core-context-menu-item>
 | 
				
			||||||
 | 
					        <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="600" [content]="prefetchText" (action)="prefetch($event)"
 | 
				
			||||||
 | 
					            [iconAction]="prefetchStatusIcon" [closeOnClick]="false">
 | 
				
			||||||
 | 
					        </core-context-menu-item>
 | 
				
			||||||
 | 
					        <core-context-menu-item *ngIf="size" [priority]="500" [content]="'core.clearstoreddata' | translate:{$a: size}"
 | 
				
			||||||
 | 
					            iconDescription="fas-archive" (action)="removeFiles($event)" iconAction="fas-trash" [closeOnClick]="false">
 | 
				
			||||||
 | 
					        </core-context-menu-item>
 | 
				
			||||||
 | 
					    </core-context-menu>
 | 
				
			||||||
 | 
					</core-navbar-buttons>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!-- Content. -->
 | 
				
			||||||
 | 
					<core-loading [hideUntil]="loaded" class="core-loading-center safe-area-page">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <ion-card class="core-warning-card" *ngIf="warning">
 | 
				
			||||||
 | 
					        <ion-icon name="fas-exclamation-triangle" slot="start"></ion-icon>
 | 
				
			||||||
 | 
					        <span [innerHTML]="warning"></span>
 | 
				
			||||||
 | 
					    </ion-card>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="addon-mod-imscp-container">
 | 
				
			||||||
 | 
					        <core-navigation-bar [previous]="previousItem" [next]="nextItem" (action)="loadItem($event)" [info]="description"
 | 
				
			||||||
 | 
					            [title]="'core.description' | translate" [component]="component" [componentId]="componentId" contextLevel="module"
 | 
				
			||||||
 | 
					            [contextInstanceId]="module?.id" [courseId]="courseId">
 | 
				
			||||||
 | 
					        </core-navigation-bar>
 | 
				
			||||||
 | 
					        <core-iframe [src]="src"></core-iframe>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</core-loading>
 | 
				
			||||||
							
								
								
									
										10
									
								
								src/addons/mod/imscp/components/index/index.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/addons/mod/imscp/components/index/index.scss
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					.addon-mod-imscp-container {
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    width: 100%;
 | 
				
			||||||
 | 
					    height: 100%;
 | 
				
			||||||
 | 
					    display: flex;
 | 
				
			||||||
 | 
					    flex-direction: column;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					core-iframe {
 | 
				
			||||||
 | 
					    flex-basis: 100%;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										176
									
								
								src/addons/mod/imscp/components/index/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								src/addons/mod/imscp/components/index/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,176 @@
 | 
				
			|||||||
 | 
					// (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 { Component, OnInit, Optional } from '@angular/core';
 | 
				
			||||||
 | 
					import { CoreSilentError } from '@classes/errors/silenterror';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					    CoreCourseModuleMainResourceComponent,
 | 
				
			||||||
 | 
					    CoreCourseResourceDownloadResult,
 | 
				
			||||||
 | 
					} 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 { ModalController } from '@singletons';
 | 
				
			||||||
 | 
					import { AddonModImscpProvider, AddonModImscp, AddonModImscpTocItem } from '../../services/imscp';
 | 
				
			||||||
 | 
					import { AddonModImscpTocComponent } from '../toc/toc';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Component that displays a IMSCP.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Component({
 | 
				
			||||||
 | 
					    selector: 'addon-mod-imscp-index',
 | 
				
			||||||
 | 
					    templateUrl: 'addon-mod-imscp-index.html',
 | 
				
			||||||
 | 
					    styleUrls: ['index.scss'],
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class AddonModImscpIndexComponent extends CoreCourseModuleMainResourceComponent implements OnInit {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    component = AddonModImscpProvider.COMPONENT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    items: AddonModImscpTocItem[] = [];
 | 
				
			||||||
 | 
					    currentItem?: string;
 | 
				
			||||||
 | 
					    src = '';
 | 
				
			||||||
 | 
					    warning = '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Initialize empty previous/next to prevent showing arrows for an instant before they're hidden.
 | 
				
			||||||
 | 
					    previousItem = '';
 | 
				
			||||||
 | 
					    nextItem = '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(@Optional() courseContentsPage?: CoreCourseContentsPage) {
 | 
				
			||||||
 | 
					        super('AddonModImscpIndexComponent', courseContentsPage);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Component being initialized.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    async ngOnInit(): Promise<void> {
 | 
				
			||||||
 | 
					        super.ngOnInit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        await this.loadContent();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            await AddonModImscp.logView(this.module!.instance!, this.module!.name);
 | 
				
			||||||
 | 
					            CoreCourse.checkModuleCompletion(this.courseId!, this.module!.completiondata);
 | 
				
			||||||
 | 
					        } catch {
 | 
				
			||||||
 | 
					            // Ignore errors.
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Perform the invalidate content function.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return Resolved when done.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected async invalidateContent(): Promise<void> {
 | 
				
			||||||
 | 
					        await AddonModImscp.invalidateContent(this.module!.id, this.courseId!);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Download imscp contents.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param refresh Whether we're refreshing data.
 | 
				
			||||||
 | 
					     * @return Promise resolved when done.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected async fetchContent(refresh = false): Promise<void> {
 | 
				
			||||||
 | 
					        let downloadResult: CoreCourseResourceDownloadResult;
 | 
				
			||||||
 | 
					        const promises: Promise<void>[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        promises.push(AddonModImscp.getImscp(this.courseId!, this.module!.id).then((imscp) => {
 | 
				
			||||||
 | 
					            this.description = imscp.intro;
 | 
				
			||||||
 | 
					            this.dataRetrieved.emit(imscp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        promises.push(this.downloadResourceIfNeeded(refresh).then((result) => {
 | 
				
			||||||
 | 
					            downloadResult = result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            await Promise.all(promises);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.items = AddonModImscp.createItemList(this.module!.contents);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (this.items.length && typeof this.currentItem == 'undefined') {
 | 
				
			||||||
 | 
					                this.currentItem = this.items[0].href;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                await this.loadItem(this.currentItem);
 | 
				
			||||||
 | 
					            } catch (error) {
 | 
				
			||||||
 | 
					                CoreDomUtils.showErrorModalDefault(error, 'addon.mod_imscp.deploymenterror', true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                throw new CoreSilentError(error);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.warning = downloadResult!.failed ? this.getErrorDownloadingSomeFilesMessage(downloadResult!.error!) : '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        } finally {
 | 
				
			||||||
 | 
					            this.fillContextMenu(refresh);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Loads an item.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param itemId Item ID.
 | 
				
			||||||
 | 
					     * @return Promise resolved when done.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    async loadItem(itemId?: string): Promise<void> {
 | 
				
			||||||
 | 
					        const src = await AddonModImscp.getIframeSrc(this.module!, itemId);
 | 
				
			||||||
 | 
					        this.currentItem = itemId;
 | 
				
			||||||
 | 
					        this.previousItem = itemId ? AddonModImscp.getPreviousItem(this.items, itemId) : '';
 | 
				
			||||||
 | 
					        this.nextItem = itemId ? AddonModImscp.getNextItem(this.items, itemId) : '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Show the TOC.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    async showToc(): Promise<void> {
 | 
				
			||||||
 | 
					        // Create the toc modal.
 | 
				
			||||||
 | 
					        const modal = await ModalController.create({
 | 
				
			||||||
 | 
					            component: AddonModImscpTocComponent,
 | 
				
			||||||
 | 
					            componentProps: {
 | 
				
			||||||
 | 
					                items: this.items,
 | 
				
			||||||
 | 
					                selected: this.currentItem,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            cssClass: 'core-modal-lateral',
 | 
				
			||||||
 | 
					            showBackdrop: true,
 | 
				
			||||||
 | 
					            backdropDismiss: true,
 | 
				
			||||||
 | 
					            // @todo enterAnimation: 'core-modal-lateral-transition',
 | 
				
			||||||
 | 
					            // @todo leaveAnimation: 'core-modal-lateral-transition',
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        await modal.present();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const result = await modal.onDidDismiss();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (result.data) {
 | 
				
			||||||
 | 
					            this.loadItem(result.data);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										25
									
								
								src/addons/mod/imscp/components/toc/toc.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/addons/mod/imscp/components/toc/toc.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					<ion-header>
 | 
				
			||||||
 | 
					    <ion-toolbar>
 | 
				
			||||||
 | 
					        <ion-buttons slot="start">
 | 
				
			||||||
 | 
					            <ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button>
 | 
				
			||||||
 | 
					        </ion-buttons>
 | 
				
			||||||
 | 
					        <ion-title>{{ 'addon.mod_imscp.toc' | translate }}</ion-title>
 | 
				
			||||||
 | 
					        <ion-buttons slot="end">
 | 
				
			||||||
 | 
					            <ion-button (click)="closeModal()" [attr.aria-label]="'core.close' | translate">
 | 
				
			||||||
 | 
					                <ion-icon name="fas-times" slot="icon-only"></ion-icon>
 | 
				
			||||||
 | 
					            </ion-button>
 | 
				
			||||||
 | 
					        </ion-buttons>
 | 
				
			||||||
 | 
					    </ion-toolbar>
 | 
				
			||||||
 | 
					</ion-header>
 | 
				
			||||||
 | 
					<ion-content>
 | 
				
			||||||
 | 
					    <nav>
 | 
				
			||||||
 | 
					        <ion-list>
 | 
				
			||||||
 | 
					            <ion-item *ngFor="let item of items" (click)="loadItem(item.href)"
 | 
				
			||||||
 | 
					                [class.core-selected-item]="selected == item.href">
 | 
				
			||||||
 | 
					                <ion-label [class.core-bold]="!item.href">
 | 
				
			||||||
 | 
					                    <span class="ion-padding-left" *ngFor="let i of getNumberForPadding(item.level)"></span>{{item.title}}
 | 
				
			||||||
 | 
					                </ion-label>
 | 
				
			||||||
 | 
					            </ion-item>
 | 
				
			||||||
 | 
					        </ion-list>
 | 
				
			||||||
 | 
					    </nav>
 | 
				
			||||||
 | 
					</ion-content>
 | 
				
			||||||
							
								
								
									
										57
									
								
								src/addons/mod/imscp/components/toc/toc.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/addons/mod/imscp/components/toc/toc.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,57 @@
 | 
				
			|||||||
 | 
					// (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 { Component, Input } from '@angular/core';
 | 
				
			||||||
 | 
					import { ModalController } from '@singletons';
 | 
				
			||||||
 | 
					import { AddonModImscpTocItem } from '../../services/imscp';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Modal to display the TOC of a imscp.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Component({
 | 
				
			||||||
 | 
					    selector: 'addon-mod-imscp-toc',
 | 
				
			||||||
 | 
					    templateUrl: 'toc.html',
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class AddonModImscpTocComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Input() items: AddonModImscpTocItem[] = [];
 | 
				
			||||||
 | 
					    @Input() selected?: string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Function called when an item is clicked.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param id ID of the clicked item.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    loadItem(id: string): void {
 | 
				
			||||||
 | 
					        ModalController.dismiss(id);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get dummy array for padding.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param n Array length.
 | 
				
			||||||
 | 
					     * @return Dummy array with n elements.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    getNumberForPadding(n: number): number[] {
 | 
				
			||||||
 | 
					        return new Array(n);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Close modal.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    closeModal(): void {
 | 
				
			||||||
 | 
					        ModalController.dismiss();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										39
									
								
								src/addons/mod/imscp/imscp-lazy.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/addons/mod/imscp/imscp-lazy.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					// (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 { AddonModImscpComponentsModule } from './components/components.module';
 | 
				
			||||||
 | 
					import { AddonModImscpIndexPage } from './pages/index/index.page';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const routes: Routes = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        path: ':courseId/:cmId',
 | 
				
			||||||
 | 
					        component: AddonModImscpIndexPage,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@NgModule({
 | 
				
			||||||
 | 
					    imports: [
 | 
				
			||||||
 | 
					        RouterModule.forChild(routes),
 | 
				
			||||||
 | 
					        CoreSharedModule,
 | 
				
			||||||
 | 
					        AddonModImscpComponentsModule,
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    declarations: [
 | 
				
			||||||
 | 
					        AddonModImscpIndexPage,
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class AddonModImscpLazyModule {}
 | 
				
			||||||
							
								
								
									
										56
									
								
								src/addons/mod/imscp/imscp.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								src/addons/mod/imscp/imscp.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,56 @@
 | 
				
			|||||||
 | 
					// (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 { APP_INITIALIZER, NgModule } from '@angular/core';
 | 
				
			||||||
 | 
					import { Routes } from '@angular/router';
 | 
				
			||||||
 | 
					import { CoreContentLinksDelegate } from '@features/contentlinks/services/contentlinks-delegate';
 | 
				
			||||||
 | 
					import { CoreCourseModuleDelegate } from '@features/course/services/module-delegate';
 | 
				
			||||||
 | 
					import { CoreCourseModulePrefetchDelegate } from '@features/course/services/module-prefetch-delegate';
 | 
				
			||||||
 | 
					import { CoreMainMenuTabRoutingModule } from '@features/mainmenu/mainmenu-tab-routing.module';
 | 
				
			||||||
 | 
					import { CorePluginFileDelegate } from '@services/plugin-file-delegate';
 | 
				
			||||||
 | 
					import { AddonModImscpComponentsModule } from './components/components.module';
 | 
				
			||||||
 | 
					import { AddonModImscpIndexLinkHandler } from './services/handlers/index-link';
 | 
				
			||||||
 | 
					import { AddonModImscpListLinkHandler } from './services/handlers/list-link';
 | 
				
			||||||
 | 
					import { AddonModImscpModuleHandler, AddonModImscpModuleHandlerService } from './services/handlers/module';
 | 
				
			||||||
 | 
					import { AddonModImscpPluginFileHandler } from './services/handlers/pluginfile';
 | 
				
			||||||
 | 
					import { AddonModImscpPrefetchHandler } from './services/handlers/prefetch';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const routes: Routes = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        path: AddonModImscpModuleHandlerService.PAGE_NAME,
 | 
				
			||||||
 | 
					        loadChildren: () => import('./imscp-lazy.module').then(m => m.AddonModImscpLazyModule),
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@NgModule({
 | 
				
			||||||
 | 
					    imports: [
 | 
				
			||||||
 | 
					        CoreMainMenuTabRoutingModule.forChild(routes),
 | 
				
			||||||
 | 
					        AddonModImscpComponentsModule,
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    providers: [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            provide: APP_INITIALIZER,
 | 
				
			||||||
 | 
					            multi: true,
 | 
				
			||||||
 | 
					            deps: [],
 | 
				
			||||||
 | 
					            useFactory: () => () => {
 | 
				
			||||||
 | 
					                CoreCourseModuleDelegate.registerHandler(AddonModImscpModuleHandler.instance);
 | 
				
			||||||
 | 
					                CoreContentLinksDelegate.registerHandler(AddonModImscpIndexLinkHandler.instance);
 | 
				
			||||||
 | 
					                CoreContentLinksDelegate.registerHandler(AddonModImscpListLinkHandler.instance);
 | 
				
			||||||
 | 
					                CoreCourseModulePrefetchDelegate.registerHandler(AddonModImscpPrefetchHandler.instance);
 | 
				
			||||||
 | 
					                CorePluginFileDelegate.registerHandler(AddonModImscpPluginFileHandler.instance);
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class AddonModImscpModule {}
 | 
				
			||||||
							
								
								
									
										6
									
								
								src/addons/mod/imscp/lang.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/addons/mod/imscp/lang.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					    "deploymenterror": "Content package error!",
 | 
				
			||||||
 | 
					    "modulenameplural": "IMS content packages",
 | 
				
			||||||
 | 
					    "showmoduledescription": "Show description",
 | 
				
			||||||
 | 
					    "toc": "TOC"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										18
									
								
								src/addons/mod/imscp/pages/index/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/addons/mod/imscp/pages/index/index.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					<ion-header>
 | 
				
			||||||
 | 
					    <ion-toolbar>
 | 
				
			||||||
 | 
					        <ion-buttons slot="start">
 | 
				
			||||||
 | 
					            <ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button>
 | 
				
			||||||
 | 
					        </ion-buttons>
 | 
				
			||||||
 | 
					        <ion-title>
 | 
				
			||||||
 | 
					            <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module?.id" [courseId]="courseId">
 | 
				
			||||||
 | 
					            </core-format-text>
 | 
				
			||||||
 | 
					        </ion-title>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <ion-buttons slot="end">
 | 
				
			||||||
 | 
					            <!-- The buttons defined by the component will be added in here. -->
 | 
				
			||||||
 | 
					        </ion-buttons>
 | 
				
			||||||
 | 
					    </ion-toolbar>
 | 
				
			||||||
 | 
					</ion-header>
 | 
				
			||||||
 | 
					<ion-content>
 | 
				
			||||||
 | 
					    <addon-mod-imscp-index [module]="module" [courseId]="courseId" (dataRetrieved)="updateData($event)"></addon-mod-imscp-index>
 | 
				
			||||||
 | 
					</ion-content>
 | 
				
			||||||
							
								
								
									
										30
									
								
								src/addons/mod/imscp/pages/index/index.page.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/addons/mod/imscp/pages/index/index.page.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					// (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 { Component, ViewChild } from '@angular/core';
 | 
				
			||||||
 | 
					import { CoreCourseModuleMainActivityPage } from '@features/course/classes/main-activity-page';
 | 
				
			||||||
 | 
					import { AddonModImscpIndexComponent } from '../../components/index/index';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Imscp that displays a IMSCP.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Component({
 | 
				
			||||||
 | 
					    selector: 'page-addon-mod-imscp-index',
 | 
				
			||||||
 | 
					    templateUrl: 'index.html',
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class AddonModImscpIndexPage extends CoreCourseModuleMainActivityPage<AddonModImscpIndexComponent> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @ViewChild(AddonModImscpIndexComponent) activityComponent?: AddonModImscpIndexComponent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										40
									
								
								src/addons/mod/imscp/services/handlers/index-link.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/addons/mod/imscp/services/handlers/index-link.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,40 @@
 | 
				
			|||||||
 | 
					// (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 { Injectable } from '@angular/core';
 | 
				
			||||||
 | 
					import { CoreContentLinksModuleIndexHandler } from '@features/contentlinks/classes/module-index-handler';
 | 
				
			||||||
 | 
					import { makeSingleton } from '@singletons';
 | 
				
			||||||
 | 
					import { AddonModImscp } from '../imscp';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Handler to treat links to IMSCP.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Injectable( { providedIn: 'root' })
 | 
				
			||||||
 | 
					export class AddonModImscpIndexLinkHandlerService extends CoreContentLinksModuleIndexHandler {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    name = 'AddonModImscpLinkHandler';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor() {
 | 
				
			||||||
 | 
					        super('AddonModImscp', 'imscp', 'i');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @inheritdoc
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    isEnabled(siteId: string): Promise<boolean> {
 | 
				
			||||||
 | 
					        return AddonModImscp.isPluginEnabled(siteId);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export const AddonModImscpIndexLinkHandler = makeSingleton(AddonModImscpIndexLinkHandlerService);
 | 
				
			||||||
							
								
								
									
										40
									
								
								src/addons/mod/imscp/services/handlers/list-link.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/addons/mod/imscp/services/handlers/list-link.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,40 @@
 | 
				
			|||||||
 | 
					// (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 { Injectable } from '@angular/core';
 | 
				
			||||||
 | 
					import { CoreContentLinksModuleListHandler } from '@features/contentlinks/classes/module-list-handler';
 | 
				
			||||||
 | 
					import { makeSingleton } from '@singletons';
 | 
				
			||||||
 | 
					import { AddonModImscp } from '../imscp';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Handler to treat links to IMSCP list page.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Injectable( { providedIn: 'root' })
 | 
				
			||||||
 | 
					export class AddonModImscpListLinkHandlerService extends CoreContentLinksModuleListHandler {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    name = 'AddonModImscpListLinkHandler';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor() {
 | 
				
			||||||
 | 
					        super('AddonModImscp', 'imscp');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @inheritdoc
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    isEnabled(siteId: string): Promise<boolean> {
 | 
				
			||||||
 | 
					        return AddonModImscp.isPluginEnabled(siteId);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export const AddonModImscpListLinkHandler = makeSingleton(AddonModImscpListLinkHandlerService);
 | 
				
			||||||
							
								
								
									
										83
									
								
								src/addons/mod/imscp/services/handlers/module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								src/addons/mod/imscp/services/handlers/module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,83 @@
 | 
				
			|||||||
 | 
					// (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 { Injectable, Type } from '@angular/core';
 | 
				
			||||||
 | 
					import { CoreCourse, CoreCourseAnyModuleData } from '@features/course/services/course';
 | 
				
			||||||
 | 
					import { CoreCourseModule } from '@features/course/services/course-helper';
 | 
				
			||||||
 | 
					import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@features/course/services/module-delegate';
 | 
				
			||||||
 | 
					import { CoreNavigationOptions, CoreNavigator } from '@services/navigator';
 | 
				
			||||||
 | 
					import { makeSingleton } from '@singletons';
 | 
				
			||||||
 | 
					import { AddonModImscpIndexComponent } from '../../components/index';
 | 
				
			||||||
 | 
					import { AddonModImscp } from '../imscp';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Handler to support IMSCP modules.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Injectable( { providedIn: 'root' })
 | 
				
			||||||
 | 
					export class AddonModImscpModuleHandlerService implements CoreCourseModuleHandler {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static readonly PAGE_NAME = 'mod_imscp';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    name = 'AddonModImscp';
 | 
				
			||||||
 | 
					    modName = 'imscp';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    supportedFeatures = {
 | 
				
			||||||
 | 
					        [CoreConstants.FEATURE_MOD_ARCHETYPE]: CoreConstants.MOD_ARCHETYPE_RESOURCE,
 | 
				
			||||||
 | 
					        [CoreConstants.FEATURE_GROUPS]: false,
 | 
				
			||||||
 | 
					        [CoreConstants.FEATURE_GROUPINGS]: false,
 | 
				
			||||||
 | 
					        [CoreConstants.FEATURE_MOD_INTRO]: true,
 | 
				
			||||||
 | 
					        [CoreConstants.FEATURE_COMPLETION_TRACKS_VIEWS]: true,
 | 
				
			||||||
 | 
					        [CoreConstants.FEATURE_GRADE_HAS_GRADE]: false,
 | 
				
			||||||
 | 
					        [CoreConstants.FEATURE_GRADE_OUTCOMES]: false,
 | 
				
			||||||
 | 
					        [CoreConstants.FEATURE_BACKUP_MOODLE2]: true,
 | 
				
			||||||
 | 
					        [CoreConstants.FEATURE_SHOW_DESCRIPTION]: true,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @inheritdoc
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    isEnabled(): Promise<boolean> {
 | 
				
			||||||
 | 
					        return AddonModImscp.isPluginEnabled();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @inheritdoc
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    getData(module: CoreCourseAnyModuleData): CoreCourseModuleHandlerData {
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					            icon: CoreCourse.getModuleIconSrc(this.modName, 'modicon' in module ? module.modicon : undefined),
 | 
				
			||||||
 | 
					            title: module.name,
 | 
				
			||||||
 | 
					            class: 'addon-mod_imscp-handler',
 | 
				
			||||||
 | 
					            showDownloadButton: true,
 | 
				
			||||||
 | 
					            action(event: Event, module: CoreCourseModule, courseId: number, options?: CoreNavigationOptions): void {
 | 
				
			||||||
 | 
					                options = options || {};
 | 
				
			||||||
 | 
					                options.params = options.params || {};
 | 
				
			||||||
 | 
					                Object.assign(options.params, { module });
 | 
				
			||||||
 | 
					                const routeParams = '/' + courseId + '/' + module.id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                CoreNavigator.navigateToSitePath(AddonModImscpModuleHandlerService.PAGE_NAME + routeParams, options);
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @inheritdoc
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    async getMainComponent(): Promise<Type<unknown> | undefined> {
 | 
				
			||||||
 | 
					        return AddonModImscpIndexComponent;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export const AddonModImscpModuleHandler = makeSingleton(AddonModImscpModuleHandlerService);
 | 
				
			||||||
							
								
								
									
										62
									
								
								src/addons/mod/imscp/services/handlers/pluginfile.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								src/addons/mod/imscp/services/handlers/pluginfile.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					// (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 { Injectable } from '@angular/core';
 | 
				
			||||||
 | 
					import { CorePluginFileHandler } from '@services/plugin-file-delegate';
 | 
				
			||||||
 | 
					import { makeSingleton } from '@singletons';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Handler to treat links to IMSCP.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Injectable( { providedIn: 'root' })
 | 
				
			||||||
 | 
					export class AddonModImscpPluginFileHandlerService implements CorePluginFileHandler {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    name = 'AddonModImscpPluginFileHandler';
 | 
				
			||||||
 | 
					    component = 'mod_imscp';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @inheritdoc
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    getComponentRevisionRegExp(args: string[]): RegExp | undefined {
 | 
				
			||||||
 | 
					        // Check filearea.
 | 
				
			||||||
 | 
					        if (args[2] == 'content') {
 | 
				
			||||||
 | 
					            // Component + Filearea + Revision
 | 
				
			||||||
 | 
					            return new RegExp('/mod_imscp/content/([0-9]+)/');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (args[2] == 'backup') {
 | 
				
			||||||
 | 
					            // Component + Filearea + Revision
 | 
				
			||||||
 | 
					            return new RegExp('/mod_imscp/backup/([0-9]+)/');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @inheritdoc
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    getComponentRevisionReplace(args: string[]): string {
 | 
				
			||||||
 | 
					        // Component + Filearea + Revision
 | 
				
			||||||
 | 
					        return '/mod_imscp/' + args[2] + '/0/';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @inheritdoc
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    async isEnabled(): Promise<boolean> {
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export const AddonModImscpPluginFileHandler = makeSingleton(AddonModImscpPluginFileHandlerService);
 | 
				
			||||||
							
								
								
									
										102
									
								
								src/addons/mod/imscp/services/handlers/prefetch.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								src/addons/mod/imscp/services/handlers/prefetch.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,102 @@
 | 
				
			|||||||
 | 
					// (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 { Injectable } from '@angular/core';
 | 
				
			||||||
 | 
					import { CoreCourseResourcePrefetchHandlerBase } from '@features/course/classes/resource-prefetch-handler';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					    CoreCourse,
 | 
				
			||||||
 | 
					    CoreCourseAnyModuleData,
 | 
				
			||||||
 | 
					    CoreCourseModuleContentFile,
 | 
				
			||||||
 | 
					    CoreCourseWSModule,
 | 
				
			||||||
 | 
					} from '@features/course/services/course';
 | 
				
			||||||
 | 
					import { CoreFilepool } from '@services/filepool';
 | 
				
			||||||
 | 
					import { CoreSites, CoreSitesReadingStrategy } from '@services/sites';
 | 
				
			||||||
 | 
					import { CoreUtils } from '@services/utils/utils';
 | 
				
			||||||
 | 
					import { CoreWSExternalFile } from '@services/ws';
 | 
				
			||||||
 | 
					import { makeSingleton } from '@singletons';
 | 
				
			||||||
 | 
					import { AddonModImscp, AddonModImscpProvider } from '../imscp';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Handler to prefetch IMSCPs.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Injectable( { providedIn: 'root' })
 | 
				
			||||||
 | 
					export class AddonModImscpPrefetchHandlerService extends CoreCourseResourcePrefetchHandlerBase {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    name = 'AddonModImscp';
 | 
				
			||||||
 | 
					    modName = 'imscp';
 | 
				
			||||||
 | 
					    component = AddonModImscpProvider.COMPONENT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @inheritdoc
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    async downloadOrPrefetch(module: CoreCourseWSModule, courseId: number, prefetch?: boolean): Promise<void> {
 | 
				
			||||||
 | 
					        const siteId = CoreSites.getCurrentSiteId();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const dirPath = await CoreFilepool.getPackageDirPathByUrl(siteId, module.url!);
 | 
				
			||||||
 | 
					        const promises: Promise<unknown>[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        promises.push(super.downloadOrPrefetch(module, courseId, prefetch, dirPath));
 | 
				
			||||||
 | 
					        promises.push(AddonModImscp.getImscp(courseId, module.id, {
 | 
				
			||||||
 | 
					            readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
 | 
				
			||||||
 | 
					            siteId,
 | 
				
			||||||
 | 
					        }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        await Promise.all(promises);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @inheritdoc
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    async getIntroFiles(module: CoreCourseAnyModuleData, courseId: number): Promise<CoreWSExternalFile[]> {
 | 
				
			||||||
 | 
					        // If not found, use undefined so module description is used.
 | 
				
			||||||
 | 
					        const imscp = await CoreUtils.ignoreErrors(AddonModImscp.getImscp(courseId, module.id));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return this.getIntroFilesFromInstance(module, imscp);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @inheritdoc
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    async invalidateContent(moduleId: number, courseId: number): Promise<void> {
 | 
				
			||||||
 | 
					        return AddonModImscp.invalidateContent(moduleId, courseId);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @inheritdoc
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    async invalidateModule(module: CoreCourseAnyModuleData, courseId: number): Promise<void> {
 | 
				
			||||||
 | 
					        const promises: Promise<unknown>[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        promises.push(AddonModImscp.invalidateImscpData(courseId));
 | 
				
			||||||
 | 
					        promises.push(CoreCourse.invalidateModule(module.id));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        await Promise.all(promises);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @inheritdoc
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    isEnabled(): Promise<boolean> {
 | 
				
			||||||
 | 
					        return AddonModImscp.isPluginEnabled();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @inheritdoc
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    isFileDownloadable(file: CoreCourseModuleContentFile): boolean {
 | 
				
			||||||
 | 
					        return AddonModImscp.isFileDownloadable(file);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export const AddonModImscpPrefetchHandler = makeSingleton(AddonModImscpPrefetchHandlerService);
 | 
				
			||||||
							
								
								
									
										399
									
								
								src/addons/mod/imscp/services/imscp.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										399
									
								
								src/addons/mod/imscp/services/imscp.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,399 @@
 | 
				
			|||||||
 | 
					// (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 { Injectable } from '@angular/core';
 | 
				
			||||||
 | 
					import { CoreError } from '@classes/errors/error';
 | 
				
			||||||
 | 
					import { CoreSite, CoreSiteWSPreSets } from '@classes/site';
 | 
				
			||||||
 | 
					import { CoreCourse, CoreCourseModuleContentFile } from '@features/course/services/course';
 | 
				
			||||||
 | 
					import { CoreCourseModule } from '@features/course/services/course-helper';
 | 
				
			||||||
 | 
					import { CoreCourseLogHelper } from '@features/course/services/log-helper';
 | 
				
			||||||
 | 
					import { CoreApp } from '@services/app';
 | 
				
			||||||
 | 
					import { CoreFilepool } from '@services/filepool';
 | 
				
			||||||
 | 
					import { CoreSitesCommonWSOptions, CoreSites } from '@services/sites';
 | 
				
			||||||
 | 
					import { CoreTextUtils } from '@services/utils/text';
 | 
				
			||||||
 | 
					import { CoreUtils } from '@services/utils/utils';
 | 
				
			||||||
 | 
					import { CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws';
 | 
				
			||||||
 | 
					import { makeSingleton } from '@singletons';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ROOT_CACHE_KEY = 'mmaModImscp:';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Service that provides some features for IMSCP.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Injectable( { providedIn: 'root' })
 | 
				
			||||||
 | 
					export class AddonModImscpProvider {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static readonly COMPONENT = 'mmaModImscp';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the IMSCP toc as an array.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param contents The module contents.
 | 
				
			||||||
 | 
					     * @return The toc.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected getToc(contents: CoreCourseModuleContentFile[]): AddonModImscpTocItemTree[] {
 | 
				
			||||||
 | 
					        if (!contents || !contents.length) {
 | 
				
			||||||
 | 
					            return [];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return CoreTextUtils.parseJSON<AddonModImscpTocItemTree[]>(contents[0].content || '');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the imscp toc as an array of items (not nested) to build the navigation tree.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param contents The module contents.
 | 
				
			||||||
 | 
					     * @return The toc as a list.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    createItemList(contents: CoreCourseModuleContentFile[]): AddonModImscpTocItem[] {
 | 
				
			||||||
 | 
					        const items: AddonModImscpTocItem[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.getToc(contents).forEach((item) => {
 | 
				
			||||||
 | 
					            items.push({ href: item.href, title: item.title, level: item.level });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            item.subitems.forEach((subitem) => {
 | 
				
			||||||
 | 
					                items.push({ href: subitem.href, title: subitem.title, level: subitem.level });
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return items;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the previous item to the given one.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param items The items list.
 | 
				
			||||||
 | 
					     * @param itemId The current item.
 | 
				
			||||||
 | 
					     * @return The previous item id.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    getPreviousItem(items: AddonModImscpTocItem[], itemId: string): string {
 | 
				
			||||||
 | 
					        const position = this.getItemPosition(items, itemId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (position == -1) {
 | 
				
			||||||
 | 
					            return '';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (let i = position - 1; i >= 0; i--) {
 | 
				
			||||||
 | 
					            if (items[i] && items[i].href) {
 | 
				
			||||||
 | 
					                return items[i].href;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return '';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the next item to the given one.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param items The items list.
 | 
				
			||||||
 | 
					     * @param itemId The current item.
 | 
				
			||||||
 | 
					     * @return The next item id.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    getNextItem(items: AddonModImscpTocItem[], itemId: string): string {
 | 
				
			||||||
 | 
					        const position = this.getItemPosition(items, itemId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (position == -1) {
 | 
				
			||||||
 | 
					            return '';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (let i = position + 1; i < items.length; i++) {
 | 
				
			||||||
 | 
					            if (items[i] && items[i].href) {
 | 
				
			||||||
 | 
					                return items[i].href;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return '';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the position of a item.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param items The items list.
 | 
				
			||||||
 | 
					     * @param itemId The item to search.
 | 
				
			||||||
 | 
					     * @return The item position.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected getItemPosition(items: AddonModImscpTocItem[], itemId: string): number {
 | 
				
			||||||
 | 
					        return items.findIndex((item) => item.href == itemId);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Check if we should ommit the file download.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param fileName The file name
 | 
				
			||||||
 | 
					     * @return True if we should ommit the file.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected checkSpecialFiles(fileName: string): boolean {
 | 
				
			||||||
 | 
					        return fileName == 'imsmanifest.xml';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get cache key for imscp data WS calls.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param courseId Course ID.
 | 
				
			||||||
 | 
					     * @return Cache key.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected getImscpDataCacheKey(courseId: number): string {
 | 
				
			||||||
 | 
					        return ROOT_CACHE_KEY +  'imscp:' + courseId;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get a imscp with key=value. If more than one is found, only the first will be returned.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param courseId Course ID.
 | 
				
			||||||
 | 
					     * @param key Name of the property to check.
 | 
				
			||||||
 | 
					     * @param value Value to search.
 | 
				
			||||||
 | 
					     * @param options Other options.
 | 
				
			||||||
 | 
					     * @return Promise resolved when the imscp is retrieved.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected async getImscpByKey(
 | 
				
			||||||
 | 
					        courseId: number,
 | 
				
			||||||
 | 
					        key: string,
 | 
				
			||||||
 | 
					        value: number,
 | 
				
			||||||
 | 
					        options: CoreSitesCommonWSOptions = {},
 | 
				
			||||||
 | 
					    ): Promise<AddonModImscpImscp> {
 | 
				
			||||||
 | 
					        const site = await CoreSites.getSite(options.siteId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const params: AddonModImscpGetImscpsByCoursesWSParams = {
 | 
				
			||||||
 | 
					            courseids: [courseId],
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const preSets: CoreSiteWSPreSets = {
 | 
				
			||||||
 | 
					            cacheKey: this.getImscpDataCacheKey(courseId),
 | 
				
			||||||
 | 
					            updateFrequency: CoreSite.FREQUENCY_RARELY,
 | 
				
			||||||
 | 
					            component: AddonModImscpProvider.COMPONENT,
 | 
				
			||||||
 | 
					            ...CoreSites.getReadingStrategyPreSets(options.readingStrategy),
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const response =
 | 
				
			||||||
 | 
					            await site.read<AddonModImscpGetImscpsByCoursesWSResponse>('mod_imscp_get_imscps_by_courses', params, preSets);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const currentImscp = response.imscps.find((imscp) => imscp[key] == value);
 | 
				
			||||||
 | 
					        if (currentImscp) {
 | 
				
			||||||
 | 
					            return currentImscp;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        throw new CoreError('Imscp not found');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get a imscp by course module ID.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param courseId Course ID.
 | 
				
			||||||
 | 
					     * @param cmId Course module ID.
 | 
				
			||||||
 | 
					     * @param options Other options.
 | 
				
			||||||
 | 
					     * @return Promise resolved when the imscp is retrieved.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    getImscp(courseId: number, cmId: number, options: CoreSitesCommonWSOptions = {}): Promise<AddonModImscpImscp> {
 | 
				
			||||||
 | 
					        return this.getImscpByKey(courseId, 'coursemodule', cmId, options);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Given a filepath, get a certain fileurl from module contents.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param items Module contents.
 | 
				
			||||||
 | 
					     * @param targetFilePath Path of the searched file.
 | 
				
			||||||
 | 
					     * @return File URL.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected getFileUrlFromContents(items: CoreCourseModuleContentFile[], targetFilePath: string): string | undefined {
 | 
				
			||||||
 | 
					        const item = items.find((item) => {
 | 
				
			||||||
 | 
					            if (item.type != 'file') {
 | 
				
			||||||
 | 
					                return false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const filePath = CoreTextUtils.concatenatePaths(item.filepath, item.filename);
 | 
				
			||||||
 | 
					            const filePathAlt = filePath.charAt(0) === '/' ? filePath.substr(1) : '/' + filePath;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Check if it's main file.
 | 
				
			||||||
 | 
					            return filePath === targetFilePath || filePathAlt === targetFilePath;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return item?.fileurl;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get src of a imscp item.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param module The module object.
 | 
				
			||||||
 | 
					     * @param itemHref Href of item to get. If not defined, gets src of main item.
 | 
				
			||||||
 | 
					     * @return Promise resolved with the item src.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    async getIframeSrc(module: CoreCourseModule, itemHref?: string): Promise<string> {
 | 
				
			||||||
 | 
					        if (!itemHref) {
 | 
				
			||||||
 | 
					            const toc = this.getToc(module.contents);
 | 
				
			||||||
 | 
					            if (!toc.length) {
 | 
				
			||||||
 | 
					                throw new CoreError('Empty TOC');
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            itemHref = toc[0].href;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const siteId = CoreSites.getCurrentSiteId();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            const dirPath = await CoreFilepool.getPackageDirUrlByUrl(siteId, module!.url!);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return CoreTextUtils.concatenatePaths(dirPath, itemHref);
 | 
				
			||||||
 | 
					        } catch (error) {
 | 
				
			||||||
 | 
					            // Error getting directory, there was an error downloading or we're in browser. Return online URL if connected.
 | 
				
			||||||
 | 
					            if (CoreApp.isOnline()) {
 | 
				
			||||||
 | 
					                const indexUrl = this.getFileUrlFromContents(module.contents, itemHref);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (indexUrl) {
 | 
				
			||||||
 | 
					                    const site = await CoreSites.getSite(siteId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    return site.checkAndFixPluginfileURL(indexUrl);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            throw error;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Invalidate the prefetched content.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param moduleId The module ID.
 | 
				
			||||||
 | 
					     * @param courseId Course ID of the module.
 | 
				
			||||||
 | 
					     * @param siteId Site ID. If not defined, current site.
 | 
				
			||||||
 | 
					     * @return Promise resolved when the content is invalidated.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    async invalidateContent(moduleId: number, courseId: number, siteId?: string): Promise<void> {
 | 
				
			||||||
 | 
					        siteId = siteId || CoreSites.getCurrentSiteId();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const promises: Promise<void>[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        promises.push(this.invalidateImscpData(courseId, siteId));
 | 
				
			||||||
 | 
					        promises.push(CoreFilepool.invalidateFilesByComponent(siteId, AddonModImscpProvider.COMPONENT, moduleId));
 | 
				
			||||||
 | 
					        promises.push(CoreCourse.invalidateModule(moduleId, siteId));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        await CoreUtils.allPromises(promises);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Invalidates imscp data.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param courseId Course ID.
 | 
				
			||||||
 | 
					     * @param siteId Site ID. If not defined, current site.
 | 
				
			||||||
 | 
					     * @return Promise resolved when the data is invalidated.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    async invalidateImscpData(courseId: number, siteId?: string): Promise<void> {
 | 
				
			||||||
 | 
					        const site = await CoreSites.getSite(siteId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        await site.invalidateWsCacheForKey(this.getImscpDataCacheKey(courseId));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Check if a file is downloadable. The file param must have 'type' and 'filename' attributes
 | 
				
			||||||
 | 
					     * like in core_course_get_contents response.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param file File to check.
 | 
				
			||||||
 | 
					     * @return True if downloadable, false otherwise.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    isFileDownloadable(file: CoreCourseModuleContentFile): boolean {
 | 
				
			||||||
 | 
					        return file.type === 'file' && !this.checkSpecialFiles(file.filename);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Return whether or not the plugin is enabled in a certain site.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param siteId Site ID. If not defined, current site.
 | 
				
			||||||
 | 
					     * @return Promise resolved with true if plugin is enabled, rejected or resolved with false otherwise.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    async isPluginEnabled(siteId?: string): Promise<boolean> {
 | 
				
			||||||
 | 
					        const site = await CoreSites.getSite(siteId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return site.canDownloadFiles();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Report a IMSCP as being viewed.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param id Module ID.
 | 
				
			||||||
 | 
					     * @param name Name of the imscp.
 | 
				
			||||||
 | 
					     * @param siteId Site ID. If not defined, current site.
 | 
				
			||||||
 | 
					     * @return Promise resolved when the WS call is successful.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    async logView(id: number, name?: string, siteId?: string): Promise<void> {
 | 
				
			||||||
 | 
					        const params: AddonModImscpViewImscpWSParams = {
 | 
				
			||||||
 | 
					            imscpid: id,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        await CoreCourseLogHelper.logSingle(
 | 
				
			||||||
 | 
					            'mod_imscp_view_imscp',
 | 
				
			||||||
 | 
					            params,
 | 
				
			||||||
 | 
					            AddonModImscpProvider.COMPONENT,
 | 
				
			||||||
 | 
					            id,
 | 
				
			||||||
 | 
					            name,
 | 
				
			||||||
 | 
					            'imscp',
 | 
				
			||||||
 | 
					            {},
 | 
				
			||||||
 | 
					            siteId,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export const AddonModImscp = makeSingleton(AddonModImscpProvider);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Params of mod_imscp_view_imscp WS.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					type AddonModImscpViewImscpWSParams = {
 | 
				
			||||||
 | 
					    imscpid: number; // Imscp instance id.
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * IMSCP returned by mod_imscp_get_imscps_by_courses.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export type AddonModImscpImscp = {
 | 
				
			||||||
 | 
					    id: number; // IMSCP id.
 | 
				
			||||||
 | 
					    coursemodule: number; // Course module id.
 | 
				
			||||||
 | 
					    course: number; // Course id.
 | 
				
			||||||
 | 
					    name: string; // Activity name.
 | 
				
			||||||
 | 
					    intro?: string; // The IMSCP intro.
 | 
				
			||||||
 | 
					    introformat?: number; // Intro format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
 | 
				
			||||||
 | 
					    introfiles?: CoreWSExternalFile[];
 | 
				
			||||||
 | 
					    revision?: number; // Revision.
 | 
				
			||||||
 | 
					    keepold?: number; // Number of old IMSCP to keep.
 | 
				
			||||||
 | 
					    structure?: string; // IMSCP structure.
 | 
				
			||||||
 | 
					    timemodified?: string; // Time of last modification.
 | 
				
			||||||
 | 
					    section?: number; // Course section id.
 | 
				
			||||||
 | 
					    visible?: boolean; // If visible.
 | 
				
			||||||
 | 
					    groupmode?: number; // Group mode.
 | 
				
			||||||
 | 
					    groupingid?: number; // Group id.
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Params of mod_imscp_get_imscps_by_courses WS.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					type AddonModImscpGetImscpsByCoursesWSParams = {
 | 
				
			||||||
 | 
					    courseids?: number[]; // Array of course ids.
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Data returned by mod_imscp_get_imscps_by_courses WS.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					type AddonModImscpGetImscpsByCoursesWSResponse = {
 | 
				
			||||||
 | 
					    imscps: AddonModImscpImscp[];
 | 
				
			||||||
 | 
					    warnings?: CoreWSExternalWarning[];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type AddonModImscpTocItem = {
 | 
				
			||||||
 | 
					    href: string;
 | 
				
			||||||
 | 
					    title: string;
 | 
				
			||||||
 | 
					    level: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type AddonModImscpTocItemTree = AddonModImscpTocItem & {
 | 
				
			||||||
 | 
					    subitems: AddonModImscpTocItem[];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -19,6 +19,7 @@ import { AddonModBookModule } from './book/book.module';
 | 
				
			|||||||
import { AddonModFolderModule } from './folder/folder.module';
 | 
					import { AddonModFolderModule } from './folder/folder.module';
 | 
				
			||||||
import { AddonModForumModule } from './forum/forum.module';
 | 
					import { AddonModForumModule } from './forum/forum.module';
 | 
				
			||||||
import { AddonModLabelModule } from './label/label.module';
 | 
					import { AddonModLabelModule } from './label/label.module';
 | 
				
			||||||
 | 
					import { AddonModImscpModule } from './imscp/imscp.module';
 | 
				
			||||||
import { AddonModLessonModule } from './lesson/lesson.module';
 | 
					import { AddonModLessonModule } from './lesson/lesson.module';
 | 
				
			||||||
import { AddonModPageModule } from './page/page.module';
 | 
					import { AddonModPageModule } from './page/page.module';
 | 
				
			||||||
import { AddonModQuizModule } from './quiz/quiz.module';
 | 
					import { AddonModQuizModule } from './quiz/quiz.module';
 | 
				
			||||||
@ -38,6 +39,7 @@ import { AddonModUrlModule } from './url/url.module';
 | 
				
			|||||||
        AddonModLabelModule,
 | 
					        AddonModLabelModule,
 | 
				
			||||||
        AddonModResourceModule,
 | 
					        AddonModResourceModule,
 | 
				
			||||||
        AddonModFolderModule,
 | 
					        AddonModFolderModule,
 | 
				
			||||||
 | 
					        AddonModImscpModule,
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    providers: [],
 | 
					    providers: [],
 | 
				
			||||||
    exports: [],
 | 
					    exports: [],
 | 
				
			||||||
 | 
				
			|||||||
@ -12,6 +12,10 @@
 | 
				
			|||||||
        clear: both;
 | 
					        clear: both;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 .core-bold {
 | 
				
			||||||
 | 
					    font-weight: bold;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.img-responsive {
 | 
					.img-responsive {
 | 
				
			||||||
    display: block;
 | 
					    display: block;
 | 
				
			||||||
    max-width: 100%;
 | 
					    max-width: 100%;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user