forked from CIT/Vmeda.Online
		
	MOBILE-2334 assign: Implement assign index page
This commit is contained in:
		
							parent
							
								
									7ab247cf7c
								
							
						
					
					
						commit
						0bb96f0e80
					
				@ -14,6 +14,7 @@
 | 
			
		||||
 | 
			
		||||
import { NgModule } from '@angular/core';
 | 
			
		||||
import { CoreCronDelegate } from '@providers/cron';
 | 
			
		||||
import { CoreCourseModuleDelegate } from '@core/course/providers/module-delegate';
 | 
			
		||||
import { CoreCourseModulePrefetchDelegate } from '@core/course/providers/module-prefetch-delegate';
 | 
			
		||||
import { AddonModAssignProvider } from './providers/assign';
 | 
			
		||||
import { AddonModAssignOfflineProvider } from './providers/assign-offline';
 | 
			
		||||
@ -23,6 +24,7 @@ import { AddonModAssignFeedbackDelegate } from './providers/feedback-delegate';
 | 
			
		||||
import { AddonModAssignSubmissionDelegate } from './providers/submission-delegate';
 | 
			
		||||
import { AddonModAssignDefaultFeedbackHandler } from './providers/default-feedback-handler';
 | 
			
		||||
import { AddonModAssignDefaultSubmissionHandler } from './providers/default-submission-handler';
 | 
			
		||||
import { AddonModAssignModuleHandler } from './providers/module-handler';
 | 
			
		||||
import { AddonModAssignPrefetchHandler } from './providers/prefetch-handler';
 | 
			
		||||
import { AddonModAssignSyncCronHandler } from './providers/sync-cron-handler';
 | 
			
		||||
 | 
			
		||||
@ -38,13 +40,16 @@ import { AddonModAssignSyncCronHandler } from './providers/sync-cron-handler';
 | 
			
		||||
        AddonModAssignSubmissionDelegate,
 | 
			
		||||
        AddonModAssignDefaultFeedbackHandler,
 | 
			
		||||
        AddonModAssignDefaultSubmissionHandler,
 | 
			
		||||
        AddonModAssignModuleHandler,
 | 
			
		||||
        AddonModAssignPrefetchHandler,
 | 
			
		||||
        AddonModAssignSyncCronHandler
 | 
			
		||||
    ]
 | 
			
		||||
})
 | 
			
		||||
export class AddonModAssignModule {
 | 
			
		||||
    constructor(prefetchDelegate: CoreCourseModulePrefetchDelegate, prefetchHandler: AddonModAssignPrefetchHandler,
 | 
			
		||||
    constructor(moduleDelegate: CoreCourseModuleDelegate, moduleHandler: AddonModAssignModuleHandler,
 | 
			
		||||
            prefetchDelegate: CoreCourseModulePrefetchDelegate, prefetchHandler: AddonModAssignPrefetchHandler,
 | 
			
		||||
            cronDelegate: CoreCronDelegate, syncHandler: AddonModAssignSyncCronHandler) {
 | 
			
		||||
        moduleDelegate.registerHandler(moduleHandler);
 | 
			
		||||
        prefetchDelegate.registerHandler(prefetchHandler);
 | 
			
		||||
        cronDelegate.register(syncHandler);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										45
									
								
								src/addon/mod/assign/components/components.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/addon/mod/assign/components/components.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,45 @@
 | 
			
		||||
// (C) Copyright 2015 Martin Dougiamas
 | 
			
		||||
//
 | 
			
		||||
// 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 { CommonModule } from '@angular/common';
 | 
			
		||||
import { IonicModule } from 'ionic-angular';
 | 
			
		||||
import { TranslateModule } from '@ngx-translate/core';
 | 
			
		||||
import { CoreComponentsModule } from '@components/components.module';
 | 
			
		||||
import { CoreDirectivesModule } from '@directives/directives.module';
 | 
			
		||||
import { CoreCourseComponentsModule } from '@core/course/components/components.module';
 | 
			
		||||
import { AddonModAssignIndexComponent } from './index/index';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
    declarations: [
 | 
			
		||||
        AddonModAssignIndexComponent
 | 
			
		||||
    ],
 | 
			
		||||
    imports: [
 | 
			
		||||
        CommonModule,
 | 
			
		||||
        IonicModule,
 | 
			
		||||
        TranslateModule.forChild(),
 | 
			
		||||
        CoreComponentsModule,
 | 
			
		||||
        CoreDirectivesModule,
 | 
			
		||||
        CoreCourseComponentsModule
 | 
			
		||||
    ],
 | 
			
		||||
    providers: [
 | 
			
		||||
    ],
 | 
			
		||||
    exports: [
 | 
			
		||||
        AddonModAssignIndexComponent
 | 
			
		||||
    ],
 | 
			
		||||
    entryComponents: [
 | 
			
		||||
        AddonModAssignIndexComponent
 | 
			
		||||
    ]
 | 
			
		||||
})
 | 
			
		||||
export class AddonModAssignComponentsModule {}
 | 
			
		||||
							
								
								
									
										87
									
								
								src/addon/mod/assign/components/index/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								src/addon/mod/assign/components/index/index.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,87 @@
 | 
			
		||||
<!-- Buttons to add to the header. -->
 | 
			
		||||
<core-navbar-buttons end>
 | 
			
		||||
    <core-context-menu>
 | 
			
		||||
        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
			
		||||
        <core-context-menu-item *ngIf="assign && (description || (assign.introattachments && assign.introattachments.length))" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
			
		||||
        <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
			
		||||
        <core-context-menu-item *ngIf="loaded && hasOffline && isOnline"  [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
			
		||||
        <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
			
		||||
        <core-context-menu-item *ngIf="size" [priority]="400" [content]="size" [iconDescription]="'cube'" (action)="removeFiles()" [iconAction]="'trash'"></core-context-menu-item>
 | 
			
		||||
    </core-context-menu>
 | 
			
		||||
</core-navbar-buttons>
 | 
			
		||||
 | 
			
		||||
<!-- Content. -->
 | 
			
		||||
<core-loading [hideUntil]="loaded" class="core-loading-center">
 | 
			
		||||
 | 
			
		||||
    <!-- Description and intro attachments. -->
 | 
			
		||||
    <ion-card *ngIf="description">
 | 
			
		||||
        <ion-item text-wrap>
 | 
			
		||||
            <core-format-text [text]="description" [component]="component" [componentId]="componentId" maxHeight="120" (click)="expandDescription($event)"></core-format-text>
 | 
			
		||||
            <ion-note *ngIf="note" item-end>{{ note }}</ion-note>
 | 
			
		||||
        </ion-item>
 | 
			
		||||
    </ion-card>
 | 
			
		||||
 | 
			
		||||
    <ion-card *ngIf="assign && assign.introattachments && assign.introattachments.length">
 | 
			
		||||
        <core-file *ngFor="let file of assign.introattachments" [file]="file" [component]="component" [componentId]="componentId"></core-file>
 | 
			
		||||
    </ion-card>
 | 
			
		||||
 | 
			
		||||
    <!-- Assign has something offline. -->
 | 
			
		||||
    <div *ngIf="hasOffline" class="core-warning-card" icon-start>
 | 
			
		||||
        <ion-icon name="warning"></ion-icon>
 | 
			
		||||
        {{ 'core.hasdatatosync' | translate:{$a: moduleName} }}
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <!-- User can view all submissions (teacher). -->
 | 
			
		||||
    <ion-card *ngIf="assign && canViewSubmissions" class="core-list-align-detail-right">
 | 
			
		||||
        <ion-item text-wrap *ngIf="timeRemaining">
 | 
			
		||||
            <h2>{{ 'addon.mod_assign.timeremaining' | translate }}</h2>
 | 
			
		||||
            <p>{{ timeRemaining }}</p>
 | 
			
		||||
        </ion-item>
 | 
			
		||||
        <ion-item text-wrap *ngIf="lateSubmissions">
 | 
			
		||||
            <h2>{{ 'addon.mod_assign.latesubmissions' | translate }}</h2>
 | 
			
		||||
            <p>{{ lateSubmissions }}</p>
 | 
			
		||||
        </ion-item>
 | 
			
		||||
 | 
			
		||||
        <!-- Summary of all submissions. -->
 | 
			
		||||
        <a ion-item text-wrap *ngIf="summary && summary.participantcount" (click)="goToSubmissionList()">
 | 
			
		||||
            <h2 *ngIf="assign.teamsubmission">{{ 'addon.mod_assign.numberofteams' | translate }}</h2>
 | 
			
		||||
            <h2 *ngIf="!assign.teamsubmission">{{ 'addon.mod_assign.numberofparticipants' | translate }}</h2>
 | 
			
		||||
            <ion-badge item-end *ngIf="showNumbers" color="primary">
 | 
			
		||||
                {{ summary.participantcount }}
 | 
			
		||||
            </ion-badge>
 | 
			
		||||
        </a>
 | 
			
		||||
 | 
			
		||||
        <!-- Summary of submissions with draft status. -->
 | 
			
		||||
        <a ion-item text-wrap *ngIf="assign.submissiondrafts && summary && summary.submissionsenabled" [attr.detail-none]="(showNumbers && !summary.submissiondraftscount) ? true : null" (click)="goToSubmissionList(submissionStatusDraft, summary.submissiondraftscount)">
 | 
			
		||||
            <h2>{{ 'addon.mod_assign.numberofdraftsubmissions' | translate }}</h2>
 | 
			
		||||
            <ion-badge item-end *ngIf="showNumbers" color="primary">
 | 
			
		||||
                {{ summary.submissiondraftscount }}
 | 
			
		||||
            </ion-badge>
 | 
			
		||||
        </a>
 | 
			
		||||
 | 
			
		||||
        <!-- Summary of submissions with submitted status. -->
 | 
			
		||||
        <a ion-item text-wrap *ngIf="summary && summary.submissionsenabled" [attr.detail-none]="(showNumbers && !summary.submissionssubmittedcount) ? true : null" (click)="goToSubmissionList(submissionStatusSubmitted, summary.submissionssubmittedcount)">
 | 
			
		||||
            <h2>{{ 'addon.mod_assign.numberofsubmittedassignments' | translate }}</h2>
 | 
			
		||||
            <ion-badge item-end *ngIf="showNumbers" color="primary">
 | 
			
		||||
                {{ summary.submissionssubmittedcount }}
 | 
			
		||||
            </ion-badge>
 | 
			
		||||
        </a>
 | 
			
		||||
 | 
			
		||||
        <!-- Summary of submissions that need grading. -->
 | 
			
		||||
        <a ion-item text-wrap *ngIf="summary && summary.submissionsenabled && !assign.teamsubmission && showNumbers" [attr.detail-none]="needsGradingAvalaible ? null : true" (click)="goToSubmissionList(needGrading, needsGradingAvalaible)">
 | 
			
		||||
            <h2>{{ 'addon.mod_assign.numberofsubmissionsneedgrading' | translate }}</h2>
 | 
			
		||||
            <ion-badge item-end color="primary">
 | 
			
		||||
                {{ summary.submissionsneedgradingcount }}
 | 
			
		||||
            </ion-badge>
 | 
			
		||||
        </a>
 | 
			
		||||
 | 
			
		||||
        <!-- Ungrouped users. -->
 | 
			
		||||
        <div *ngIf="assign.teamsubmission && summary && summary.warnofungroupedusers" class="core-info-card" icon-start>
 | 
			
		||||
            <ion-icon name="information"></ion-icon>
 | 
			
		||||
            {{ 'addon.mod_assign.ungroupedusers' | translate }}
 | 
			
		||||
        </div>
 | 
			
		||||
    </ion-card>
 | 
			
		||||
 | 
			
		||||
    <!-- @todo <addon-mod-assign-submission *ngIf="!canViewSubmissions" [courseId]="courseId" [moduleId]="module.id"></addon-mod-assign-submission> -->
 | 
			
		||||
 | 
			
		||||
</core-loading>
 | 
			
		||||
							
								
								
									
										312
									
								
								src/addon/mod/assign/components/index/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										312
									
								
								src/addon/mod/assign/components/index/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,312 @@
 | 
			
		||||
// (C) Copyright 2015 Martin Dougiamas
 | 
			
		||||
//
 | 
			
		||||
// 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, Optional, Injector } from '@angular/core';
 | 
			
		||||
import { Content, NavController } from 'ionic-angular';
 | 
			
		||||
import { CoreGroupsProvider } from '@providers/groups';
 | 
			
		||||
import { CoreTimeUtilsProvider } from '@providers/utils/time';
 | 
			
		||||
import { CoreCourseModuleMainActivityComponent } from '@core/course/classes/main-activity-component';
 | 
			
		||||
import { AddonModAssignProvider } from '../../providers/assign';
 | 
			
		||||
import { AddonModAssignHelperProvider } from '../../providers/helper';
 | 
			
		||||
import { AddonModAssignOfflineProvider } from '../../providers/assign-offline';
 | 
			
		||||
import { AddonModAssignSyncProvider } from '../../providers/assign-sync';
 | 
			
		||||
import * as moment from 'moment';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Component that displays an assignment.
 | 
			
		||||
 */
 | 
			
		||||
@Component({
 | 
			
		||||
    selector: 'addon-mod-assign-index',
 | 
			
		||||
    templateUrl: 'index.html',
 | 
			
		||||
})
 | 
			
		||||
export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityComponent {
 | 
			
		||||
    component = AddonModAssignProvider.COMPONENT;
 | 
			
		||||
    moduleName = 'assign';
 | 
			
		||||
 | 
			
		||||
    assign: any; // The assign object.
 | 
			
		||||
    canViewSubmissions: boolean; // Whether the user can view all submissions.
 | 
			
		||||
    timeRemaining: string; // Message about time remaining to submit.
 | 
			
		||||
    lateSubmissions: string; // Message about late submissions.
 | 
			
		||||
    showNumbers = true; // Whether to show number of submissions with each status.
 | 
			
		||||
    summary: any; // The summary.
 | 
			
		||||
    needsGradingAvalaible: boolean; // Whether we can see the submissions that need grading.
 | 
			
		||||
 | 
			
		||||
    // Status.
 | 
			
		||||
    submissionStatusSubmitted = AddonModAssignProvider.SUBMISSION_STATUS_SUBMITTED;
 | 
			
		||||
    submissionStatusDraft = AddonModAssignProvider.SUBMISSION_STATUS_DRAFT;
 | 
			
		||||
    needGrading = AddonModAssignProvider.NEED_GRADING;
 | 
			
		||||
 | 
			
		||||
    protected userId: number; // Current user ID.
 | 
			
		||||
    protected syncEventName = AddonModAssignSyncProvider.AUTO_SYNCED;
 | 
			
		||||
 | 
			
		||||
    // Observers.
 | 
			
		||||
    protected savedObserver;
 | 
			
		||||
    protected submittedObserver;
 | 
			
		||||
    protected gradedObserver;
 | 
			
		||||
 | 
			
		||||
    constructor(injector: Injector, protected assignProvider: AddonModAssignProvider, @Optional() content: Content,
 | 
			
		||||
            protected assignHelper: AddonModAssignHelperProvider, protected assignOffline: AddonModAssignOfflineProvider,
 | 
			
		||||
            protected syncProvider: AddonModAssignSyncProvider, protected timeUtils: CoreTimeUtilsProvider,
 | 
			
		||||
            protected groupsProvider: CoreGroupsProvider, protected navCtrl: NavController) {
 | 
			
		||||
        super(injector, content);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Component being initialized.
 | 
			
		||||
     */
 | 
			
		||||
    ngOnInit(): void {
 | 
			
		||||
        super.ngOnInit();
 | 
			
		||||
 | 
			
		||||
        this.userId = this.sitesProvider.getCurrentSiteUserId();
 | 
			
		||||
 | 
			
		||||
        this.loadContent(false, true).then(() => {
 | 
			
		||||
            this.assignProvider.logView(this.assign.id).then(() => {
 | 
			
		||||
                this.courseProvider.checkModuleCompletion(this.courseId, this.module.completionstatus);
 | 
			
		||||
            }).catch(() => {
 | 
			
		||||
                // Ignore errors.
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            if (!this.canViewSubmissions) {
 | 
			
		||||
                // User can only see his submission, log view the user submission.
 | 
			
		||||
                this.assignProvider.logSubmissionView(this.assign.id).catch(() => {
 | 
			
		||||
                    // Ignore errors.
 | 
			
		||||
                });
 | 
			
		||||
            } else {
 | 
			
		||||
                // User can see all submissions, log grading view.
 | 
			
		||||
                this.assignProvider.logGradingView(this.assign.id).catch(() => {
 | 
			
		||||
                    // Ignore errors.
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Listen to events.
 | 
			
		||||
        this.savedObserver = this.eventsProvider.on(AddonModAssignProvider.SUBMISSION_SAVED_EVENT, (data) => {
 | 
			
		||||
            if (this.assign && data.assignmentId == this.assign.id && data.userId == this.userId) {
 | 
			
		||||
                // Assignment submission saved, refresh data.
 | 
			
		||||
                this.showLoadingAndRefresh(true, false);
 | 
			
		||||
            }
 | 
			
		||||
        }, this.siteId);
 | 
			
		||||
 | 
			
		||||
        this.submittedObserver = this.eventsProvider.on(AddonModAssignProvider.SUBMITTED_FOR_GRADING_EVENT, (data) => {
 | 
			
		||||
            if (this.assign && data.assignmentId == this.assign.id && data.userId == this.userId) {
 | 
			
		||||
                // Assignment submitted, check completion.
 | 
			
		||||
                this.courseProvider.checkModuleCompletion(this.courseId, this.module.completionstatus);
 | 
			
		||||
            }
 | 
			
		||||
        }, this.siteId);
 | 
			
		||||
 | 
			
		||||
        this.gradedObserver = this.eventsProvider.on(AddonModAssignProvider.GRADED_EVENT, (data) => {
 | 
			
		||||
            if (this.assign && data.assignmentId == this.assign.id && data.userId == this.userId) {
 | 
			
		||||
                // Assignment graded, refresh data.
 | 
			
		||||
                this.showLoadingAndRefresh(true, false);
 | 
			
		||||
            }
 | 
			
		||||
        }, this.siteId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Expand the description.
 | 
			
		||||
     */
 | 
			
		||||
    expandDescription(ev?: Event): void {
 | 
			
		||||
        ev && ev.preventDefault();
 | 
			
		||||
        ev && ev.stopPropagation();
 | 
			
		||||
 | 
			
		||||
        if (this.assign && (this.description || this.assign.introattachments)) {
 | 
			
		||||
            this.textUtils.expandText(this.translate.instant('core.description'), this.description, this.component,
 | 
			
		||||
                    this.module.id, this.assign.introattachments);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get assignment data.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {boolean} [refresh=false] If it's refreshing content.
 | 
			
		||||
     * @param {boolean} [sync=false] If the refresh is needs syncing.
 | 
			
		||||
     * @param {boolean} [showErrors=false] If show errors to the user of hide them.
 | 
			
		||||
     * @return {Promise<any>} Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    protected fetchContent(refresh: boolean = false, sync: boolean = false, showErrors: boolean = false): Promise<any> {
 | 
			
		||||
 | 
			
		||||
        // Get assignment data.
 | 
			
		||||
        return this.assignProvider.getAssignment(this.courseId, this.module.id).then((assignData) => {
 | 
			
		||||
            this.assign = assignData;
 | 
			
		||||
 | 
			
		||||
            this.dataRetrieved.emit(this.assign);
 | 
			
		||||
            this.description = this.assign.intro || this.description;
 | 
			
		||||
 | 
			
		||||
            if (sync) {
 | 
			
		||||
                // Try to synchronize the assign.
 | 
			
		||||
                return this.syncActivity(showErrors).catch(() => {
 | 
			
		||||
                    // Ignore errors.
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }).then(() => {
 | 
			
		||||
            // Check if there's any offline data for this assign.
 | 
			
		||||
            return this.assignOffline.hasAssignOfflineData(this.assign.id);
 | 
			
		||||
        }).then((hasOffline) => {
 | 
			
		||||
            this.hasOffline = hasOffline;
 | 
			
		||||
 | 
			
		||||
            // Get assignment submissions.
 | 
			
		||||
            return this.assignProvider.getSubmissions(this.assign.id).then((data) => {
 | 
			
		||||
                const time = this.timeUtils.timestamp();
 | 
			
		||||
 | 
			
		||||
                this.canViewSubmissions = data.canviewsubmissions;
 | 
			
		||||
 | 
			
		||||
                if (data.canviewsubmissions) {
 | 
			
		||||
 | 
			
		||||
                    // Calculate the messages to display about time remaining and late submissions.
 | 
			
		||||
                    if (this.assign.duedate > 0) {
 | 
			
		||||
                        if (this.assign.duedate - time <= 0) {
 | 
			
		||||
                            this.timeRemaining = this.translate.instant('addon.mod_assign.assignmentisdue');
 | 
			
		||||
                        } else {
 | 
			
		||||
                            this.timeRemaining = this.timeUtils.formatDuration(this.assign.duedate - time, 3);
 | 
			
		||||
 | 
			
		||||
                            if (this.assign.cutoffdate) {
 | 
			
		||||
                                if (this.assign.cutoffdate > time) {
 | 
			
		||||
                                    const dateFormat = this.translate.instant('core.dfmediumdate');
 | 
			
		||||
 | 
			
		||||
                                    this.lateSubmissions = this.translate.instant('addon.mod_assign.latesubmissionsaccepted',
 | 
			
		||||
                                            {$a: moment(this.assign.cutoffdate * 1000).format(dateFormat)});
 | 
			
		||||
                                } else {
 | 
			
		||||
                                    this.lateSubmissions = this.translate.instant('addon.mod_assign.nomoresubmissionsaccepted');
 | 
			
		||||
                                }
 | 
			
		||||
                            } else {
 | 
			
		||||
                                this.lateSubmissions = '';
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        this.timeRemaining = '';
 | 
			
		||||
                        this.lateSubmissions = '';
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // Check if groupmode is enabled to avoid showing wrong numbers.
 | 
			
		||||
                    return this.groupsProvider.activityHasGroups(this.assign.cmid).then((hasGroups) => {
 | 
			
		||||
                        this.showNumbers = !hasGroups;
 | 
			
		||||
 | 
			
		||||
                        return this.assignProvider.getSubmissionStatus(this.assign.id).then((response) => {
 | 
			
		||||
                            this.summary = response.gradingsummary;
 | 
			
		||||
 | 
			
		||||
                            this.needsGradingAvalaible = response.gradingsummary.submissionsneedgradingcount > 0 &&
 | 
			
		||||
                                    this.sitesProvider.getCurrentSite().isVersionGreaterEqualThan('3.2');
 | 
			
		||||
                        });
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        }).then(() => {
 | 
			
		||||
            // All data obtained, now fill the context menu.
 | 
			
		||||
            this.fillContextMenu(refresh);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Go to view a list of submissions.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string} status Status to see.
 | 
			
		||||
     * @param {number} count Number of submissions with the status.
 | 
			
		||||
     */
 | 
			
		||||
    goToSubmissionList(status: string, count: number): void {
 | 
			
		||||
        if (typeof status == 'undefined') {
 | 
			
		||||
            this.navCtrl.push('AddonModAssignSubmissionListPage', {
 | 
			
		||||
                courseId: this.courseId,
 | 
			
		||||
                moduleId: this.module.id,
 | 
			
		||||
                moduleName: this.moduleName
 | 
			
		||||
            });
 | 
			
		||||
        } else if (count || !this.showNumbers) {
 | 
			
		||||
            this.navCtrl.push('AddonModAssignSubmissionListPage', {
 | 
			
		||||
                status: status,
 | 
			
		||||
                courseId: this.courseId,
 | 
			
		||||
                moduleId: this.module.id,
 | 
			
		||||
                moduleName: this.moduleName
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks if sync has succeed from result sync data.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {any} result Data returned by the sync function.
 | 
			
		||||
     * @return {boolean} If succeed or not.
 | 
			
		||||
     */
 | 
			
		||||
    protected hasSyncSucceed(result: any): boolean {
 | 
			
		||||
        if (result.updated) {
 | 
			
		||||
            // Sync done, trigger event.
 | 
			
		||||
            this.eventsProvider.trigger(AddonModAssignSyncProvider.MANUAL_SYNCED, {
 | 
			
		||||
                assignId: this.assign.id,
 | 
			
		||||
                warnings: result.warnings
 | 
			
		||||
            }, this.siteId);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return result.updated;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Perform the invalidate content function.
 | 
			
		||||
     *
 | 
			
		||||
     * @return {Promise<any>} Resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    protected invalidateContent(): Promise<any> {
 | 
			
		||||
        const promises = [];
 | 
			
		||||
 | 
			
		||||
        promises.push(this.assignProvider.invalidateAssignmentData(this.courseId));
 | 
			
		||||
 | 
			
		||||
        if (this.assign) {
 | 
			
		||||
            promises.push(this.assignProvider.invalidateAllSubmissionData(this.assign.id));
 | 
			
		||||
 | 
			
		||||
            if (this.canViewSubmissions) {
 | 
			
		||||
                promises.push(this.assignProvider.invalidateSubmissionStatusData(this.assign.id));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return Promise.all(promises).finally(() => {
 | 
			
		||||
            // @todo $scope.$broadcast(mmaModAssignSubmissionInvalidatedEvent);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Compares sync event data with current data to check if refresh content is needed.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {any} syncEventData Data receiven on sync observer.
 | 
			
		||||
     * @return {boolean}          True if refresh is needed, false otherwise.
 | 
			
		||||
     */
 | 
			
		||||
    protected isRefreshSyncNeeded(syncEventData: any): boolean {
 | 
			
		||||
        if (this.assign && syncEventData.assignId == this.assign.id) {
 | 
			
		||||
            if (syncEventData.warnings && syncEventData.warnings.length) {
 | 
			
		||||
                // Show warnings.
 | 
			
		||||
                this.domUtils.showErrorModal(syncEventData.warnings[0]);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Performs the sync of the activity.
 | 
			
		||||
     *
 | 
			
		||||
     * @return {Promise<any>} Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    protected sync(): Promise<any> {
 | 
			
		||||
        return this.syncProvider.syncAssign(this.assign.id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Component being destroyed.
 | 
			
		||||
     */
 | 
			
		||||
    ngOnDestroy(): void {
 | 
			
		||||
        super.ngOnDestroy();
 | 
			
		||||
 | 
			
		||||
        this.savedObserver && this.savedObserver.off();
 | 
			
		||||
        this.submittedObserver && this.submittedObserver.off();
 | 
			
		||||
        this.gradedObserver && this.gradedObserver.off();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										99
									
								
								src/addon/mod/assign/lang/en.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								src/addon/mod/assign/lang/en.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,99 @@
 | 
			
		||||
{
 | 
			
		||||
    "acceptsubmissionstatement": "Please accept the submission statement.",
 | 
			
		||||
    "addattempt": "Allow another attempt",
 | 
			
		||||
    "addnewattempt": "Add a new attempt",
 | 
			
		||||
    "addnewattemptfromprevious": "Add a new attempt based on previous submission",
 | 
			
		||||
    "addsubmission": "Add submission",
 | 
			
		||||
    "allowsubmissionsfromdate": "Allow submissions from",
 | 
			
		||||
    "allowsubmissionsfromdatesummary": "This assignment will accept submissions from <strong>{{$a}}</strong>",
 | 
			
		||||
    "allowsubmissionsanddescriptionfromdatesummary": "The assignment details and submission form will be available from <strong>{{$a}}</strong>",
 | 
			
		||||
    "applytoteam": "Apply grades and feedback to entire group",
 | 
			
		||||
    "assignmentisdue": "Assignment is due",
 | 
			
		||||
    "attemptnumber": "Attempt number",
 | 
			
		||||
    "attemptreopenmethod": "Attempts reopened",
 | 
			
		||||
    "attemptreopenmethod_manual": "Manually",
 | 
			
		||||
    "attemptreopenmethod_untilpass": "Automatically until pass",
 | 
			
		||||
    "attemptsettings": "Attempt settings",
 | 
			
		||||
    "cannotgradefromapp": "Certain grading methods are not yet supported by the app and cannot be modified.",
 | 
			
		||||
    "cannoteditduetostatementsubmission": "You can't add or edit a submission in the app because the submission statement could not be retrieved from the site.",
 | 
			
		||||
    "cannotsubmitduetostatementsubmission": "You can't make a submission in the app because the submission statement could not be retrieved from the site.",
 | 
			
		||||
    "confirmsubmission": "Are you sure you want to submit your work for grading? You will not be able to make any more changes.",
 | 
			
		||||
    "currentgrade": "Current grade in gradebook",
 | 
			
		||||
    "cutoffdate": "Cut-off date",
 | 
			
		||||
    "currentattempt": "This is attempt {{$a}}.",
 | 
			
		||||
    "currentattemptof": "This is attempt {{$a.attemptnumber}} ( {{$a.maxattempts}} attempts allowed ).",
 | 
			
		||||
    "defaultteam": "Default group",
 | 
			
		||||
    "duedate": "Due date",
 | 
			
		||||
    "duedateno": "No due date",
 | 
			
		||||
    "duedatereached": "The due date for this assignment has now passed",
 | 
			
		||||
    "editingstatus": "Editing status",
 | 
			
		||||
    "editsubmission": "Edit submission",
 | 
			
		||||
    "erroreditpluginsnotsupported": "You can't add or edit a submission in the app because certain plugins are not yet supported for editing.",
 | 
			
		||||
    "errorshowinginformation": "Submission information cannot be displayed.",
 | 
			
		||||
    "extensionduedate": "Extension due date",
 | 
			
		||||
    "feedbacknotsupported": "This feedback is not supported by the app and may not contain all the information.",
 | 
			
		||||
    "grade": "Grade",
 | 
			
		||||
    "graded": "Graded",
 | 
			
		||||
    "gradedby": "Graded by",
 | 
			
		||||
    "gradenotsynced": "Grade not synced",
 | 
			
		||||
    "gradedon": "Graded on",
 | 
			
		||||
    "gradeoutof": "Grade out of {{$a}}",
 | 
			
		||||
    "gradingstatus": "Grading status",
 | 
			
		||||
    "groupsubmissionsettings": "Group submission settings",
 | 
			
		||||
    "hiddenuser": "Participant",
 | 
			
		||||
    "latesubmissions": "Late submissions",
 | 
			
		||||
    "latesubmissionsaccepted": "Allowed until {{$a}}",
 | 
			
		||||
    "markingworkflowstate": "Marking workflow state",
 | 
			
		||||
    "markingworkflowstateinmarking": "In marking",
 | 
			
		||||
    "markingworkflowstateinreview": "In review",
 | 
			
		||||
    "markingworkflowstatenotmarked": "Not marked",
 | 
			
		||||
    "markingworkflowstatereadyforreview": "Marking completed",
 | 
			
		||||
    "markingworkflowstatereadyforrelease": "Ready for release",
 | 
			
		||||
    "markingworkflowstatereleased": "Released",
 | 
			
		||||
    "multipleteams": "Member of more than one group",
 | 
			
		||||
    "noattempt": "No attempt",
 | 
			
		||||
    "nomoresubmissionsaccepted": "Only allowed for participants who have been granted an extension",
 | 
			
		||||
    "noonlinesubmissions": "This assignment does not require you to submit anything online",
 | 
			
		||||
    "nosubmission": "Nothing has been submitted for this assignment",
 | 
			
		||||
    "notallparticipantsareshown": "Participants who have not made a submission are not shown.",
 | 
			
		||||
    "noteam": "Not a member of any group",
 | 
			
		||||
    "notgraded": "Not graded",
 | 
			
		||||
    "numberofdraftsubmissions": "Drafts",
 | 
			
		||||
    "numberofparticipants": "Participants",
 | 
			
		||||
    "numberofsubmittedassignments": "Submitted",
 | 
			
		||||
    "numberofsubmissionsneedgrading": "Needs grading",
 | 
			
		||||
    "numberofteams": "Groups",
 | 
			
		||||
    "numwords": "({{$a}} words)",
 | 
			
		||||
    "outof": "{{$a.current}} out of {{$a.total}}",
 | 
			
		||||
    "overdue": "<font color=\"red\">Assignment is overdue by: {{$a}}</font>",
 | 
			
		||||
    "savechanges": "Save changes",
 | 
			
		||||
    "submissioneditable": "Student can edit this submission",
 | 
			
		||||
    "submissionnoteditable": "Student cannot edit this submission",
 | 
			
		||||
    "submissionnotsupported": "This submission is not supported by the app and may not contain all the information.",
 | 
			
		||||
    "submission": "Submission",
 | 
			
		||||
    "submissionslocked": "This assignment is not accepting submissions",
 | 
			
		||||
    "submissionstatus_draft": "Draft (not submitted)",
 | 
			
		||||
    "submissionstatusheading": "Submission status",
 | 
			
		||||
    "submissionstatus_marked": "Graded",
 | 
			
		||||
    "submissionstatus_new": "No submission",
 | 
			
		||||
    "submissionstatus_reopened": "Reopened",
 | 
			
		||||
    "submissionstatus_submitted": "Submitted for grading",
 | 
			
		||||
    "submissionstatus_": "No submission",
 | 
			
		||||
    "submissionstatus": "Submission status",
 | 
			
		||||
    "submissionstatusheading": "Submission status",
 | 
			
		||||
    "submissionteam": "Group",
 | 
			
		||||
    "submitassignment_help": "Once this assignment is submitted you will not be able to make any more changes.",
 | 
			
		||||
    "submitassignment": "Submit assignment",
 | 
			
		||||
    "submittedearly": "Assignment was submitted {{$a}} early",
 | 
			
		||||
    "submittedlate": "Assignment was submitted {{$a}} late",
 | 
			
		||||
    "timemodified": "Last modified",
 | 
			
		||||
    "timeremaining": "Time remaining",
 | 
			
		||||
    "ungroupedusers": "The setting 'Require group to make submission' is enabled and some users are either not a member of any group, or are a member of more than one group, so are unable to make submissions.",
 | 
			
		||||
    "unlimitedattempts": "Unlimited",
 | 
			
		||||
    "userwithid": "User with ID {{id}}",
 | 
			
		||||
    "userswhoneedtosubmit": "Users who need to submit: {{$a}}",
 | 
			
		||||
    "viewsubmission": "View submission",
 | 
			
		||||
    "warningsubmissionmodified": "The user submission was modified on the site.",
 | 
			
		||||
    "warningsubmissiongrademodified": "The submission grade was modified on the site.",
 | 
			
		||||
    "wordlimit": "Word limit"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										16
									
								
								src/addon/mod/assign/pages/index/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/addon/mod/assign/pages/index/index.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
<ion-header>
 | 
			
		||||
    <ion-navbar>
 | 
			
		||||
        <ion-title><core-format-text [text]="title"></core-format-text></ion-title>
 | 
			
		||||
 | 
			
		||||
        <ion-buttons end>
 | 
			
		||||
            <!-- The buttons defined by the component will be added in here. -->
 | 
			
		||||
        </ion-buttons>
 | 
			
		||||
    </ion-navbar>
 | 
			
		||||
</ion-header>
 | 
			
		||||
<ion-content>
 | 
			
		||||
    <ion-refresher [enabled]="assignComponent.loaded" (ionRefresh)="assignComponent.doRefresh($event)">
 | 
			
		||||
        <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
 | 
			
		||||
    </ion-refresher>
 | 
			
		||||
 | 
			
		||||
    <addon-mod-assign-index [module]="module" [courseId]="courseId" (dataRetrieved)="updateData($event)"></addon-mod-assign-index>
 | 
			
		||||
</ion-content>
 | 
			
		||||
							
								
								
									
										33
									
								
								src/addon/mod/assign/pages/index/index.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/addon/mod/assign/pages/index/index.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,33 @@
 | 
			
		||||
// (C) Copyright 2015 Martin Dougiamas
 | 
			
		||||
//
 | 
			
		||||
// 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 { IonicPageModule } from 'ionic-angular';
 | 
			
		||||
import { TranslateModule } from '@ngx-translate/core';
 | 
			
		||||
import { CoreDirectivesModule } from '@directives/directives.module';
 | 
			
		||||
import { AddonModAssignComponentsModule } from '../../components/components.module';
 | 
			
		||||
import { AddonModAssignIndexPage } from './index';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
    declarations: [
 | 
			
		||||
        AddonModAssignIndexPage,
 | 
			
		||||
    ],
 | 
			
		||||
    imports: [
 | 
			
		||||
        CoreDirectivesModule,
 | 
			
		||||
        AddonModAssignComponentsModule,
 | 
			
		||||
        IonicPageModule.forChild(AddonModAssignIndexPage),
 | 
			
		||||
        TranslateModule.forChild()
 | 
			
		||||
    ],
 | 
			
		||||
})
 | 
			
		||||
export class AddonModAssignIndexPageModule {}
 | 
			
		||||
							
								
								
									
										48
									
								
								src/addon/mod/assign/pages/index/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/addon/mod/assign/pages/index/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,48 @@
 | 
			
		||||
// (C) Copyright 2015 Martin Dougiamas
 | 
			
		||||
//
 | 
			
		||||
// 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 { IonicPage, NavParams } from 'ionic-angular';
 | 
			
		||||
import { AddonModAssignIndexComponent } from '../../components/index/index';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Page that displays an assign.
 | 
			
		||||
 */
 | 
			
		||||
@IonicPage({ segment: 'addon-mod-assign-index' })
 | 
			
		||||
@Component({
 | 
			
		||||
    selector: 'page-addon-mod-assign-index',
 | 
			
		||||
    templateUrl: 'index.html',
 | 
			
		||||
})
 | 
			
		||||
export class AddonModAssignIndexPage {
 | 
			
		||||
    @ViewChild(AddonModAssignIndexComponent) assignComponent: AddonModAssignIndexComponent;
 | 
			
		||||
 | 
			
		||||
    title: string;
 | 
			
		||||
    module: any;
 | 
			
		||||
    courseId: number;
 | 
			
		||||
 | 
			
		||||
    constructor(navParams: NavParams) {
 | 
			
		||||
        this.module = navParams.get('module') || {};
 | 
			
		||||
        this.courseId = navParams.get('courseId');
 | 
			
		||||
        this.title = this.module.name;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Update some data based on the assign instance.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {any} assign Assign instance.
 | 
			
		||||
     */
 | 
			
		||||
    updateData(assign: any): void {
 | 
			
		||||
        this.title = assign.name || this.title;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								src/addon/mod/assign/providers/index-link-handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/addon/mod/assign/providers/index-link-handler.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
			
		||||
// (C) Copyright 2015 Martin Dougiamas
 | 
			
		||||
//
 | 
			
		||||
// 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 '@core/contentlinks/classes/module-index-handler';
 | 
			
		||||
import { CoreCourseHelperProvider } from '@core/course/providers/helper';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handler to treat links to assign index page.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class AddonModAssignIndexLinkHandler extends CoreContentLinksModuleIndexHandler {
 | 
			
		||||
    name = 'AddonModAssignIndexLinkHandler';
 | 
			
		||||
 | 
			
		||||
    constructor(courseHelper: CoreCourseHelperProvider) {
 | 
			
		||||
        super(courseHelper, 'AddonModAssign', 'assign');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										72
									
								
								src/addon/mod/assign/providers/module-handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								src/addon/mod/assign/providers/module-handler.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,72 @@
 | 
			
		||||
// (C) Copyright 2015 Martin Dougiamas
 | 
			
		||||
//
 | 
			
		||||
// 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 { NavController, NavOptions } from 'ionic-angular';
 | 
			
		||||
import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@core/course/providers/module-delegate';
 | 
			
		||||
import { CoreCourseProvider } from '@core/course/providers/course';
 | 
			
		||||
import { AddonModAssignProvider } from './assign';
 | 
			
		||||
import { AddonModAssignIndexComponent } from '../components/index/index';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handler to support assign modules.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class AddonModAssignModuleHandler implements CoreCourseModuleHandler {
 | 
			
		||||
    name = 'AddonModAssign';
 | 
			
		||||
    modName = 'assign';
 | 
			
		||||
 | 
			
		||||
    constructor(private courseProvider: CoreCourseProvider, private assignProvider: AddonModAssignProvider) { }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if the handler is enabled on a site level.
 | 
			
		||||
     *
 | 
			
		||||
     * @return {boolean} Whether or not the handler is enabled on a site level.
 | 
			
		||||
     */
 | 
			
		||||
    isEnabled(): boolean {
 | 
			
		||||
        return this.assignProvider.isPluginEnabled();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the data required to display the module in the course contents view.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {any} module The module object.
 | 
			
		||||
     * @param {number} courseId The course ID.
 | 
			
		||||
     * @param {number} sectionId The section ID.
 | 
			
		||||
     * @return {CoreCourseModuleHandlerData} Data to render the module.
 | 
			
		||||
     */
 | 
			
		||||
    getData(module: any, courseId: number, sectionId: number): CoreCourseModuleHandlerData {
 | 
			
		||||
        return {
 | 
			
		||||
            icon: this.courseProvider.getModuleIconSrc('assign'),
 | 
			
		||||
            title: module.name,
 | 
			
		||||
            class: 'addon-mod_assign-handler',
 | 
			
		||||
            showDownloadButton: true,
 | 
			
		||||
            action(event: Event, navCtrl: NavController, module: any, courseId: number, options: NavOptions): void {
 | 
			
		||||
                navCtrl.push('AddonModAssignIndexPage', {module: module, courseId: courseId}, options);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the component to render the module. This is needed to support singleactivity course format.
 | 
			
		||||
     * The component returned must implement CoreCourseModuleMainComponent.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {any} course The course object.
 | 
			
		||||
     * @param {any} module The module object.
 | 
			
		||||
     * @return {any} The component to use, undefined if not found.
 | 
			
		||||
     */
 | 
			
		||||
    getMainComponent(course: any, module: any): any {
 | 
			
		||||
        return AddonModAssignIndexComponent;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -48,9 +48,9 @@ export class AddonModChoiceIndexComponent extends CoreCourseModuleMainActivityCo
 | 
			
		||||
    protected hasAnsweredOnline = false;
 | 
			
		||||
    protected now: number;
 | 
			
		||||
 | 
			
		||||
    constructor(injector: Injector, private choiceProvider: AddonModChoiceProvider, @Optional() private content: Content,
 | 
			
		||||
    constructor(injector: Injector, private choiceProvider: AddonModChoiceProvider, @Optional() content: Content,
 | 
			
		||||
            private choiceOffline: AddonModChoiceOfflineProvider, private choiceSync: AddonModChoiceSyncProvider) {
 | 
			
		||||
        super(injector);
 | 
			
		||||
        super(injector, content);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -65,11 +65,11 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity
 | 
			
		||||
 | 
			
		||||
    protected submitObserver: any;
 | 
			
		||||
 | 
			
		||||
    constructor(injector: Injector, private feedbackProvider: AddonModFeedbackProvider, @Optional() private content: Content,
 | 
			
		||||
    constructor(injector: Injector, private feedbackProvider: AddonModFeedbackProvider, @Optional() content: Content,
 | 
			
		||||
            private feedbackOffline: AddonModFeedbackOfflineProvider, private groupsProvider: CoreGroupsProvider,
 | 
			
		||||
            private feedbackSync: AddonModFeedbackSyncProvider, private navCtrl: NavController,
 | 
			
		||||
            private feedbackHelper: AddonModFeedbackHelperProvider) {
 | 
			
		||||
        super(injector);
 | 
			
		||||
        super(injector, content);
 | 
			
		||||
 | 
			
		||||
        // Listen for form submit events.
 | 
			
		||||
        this.submitObserver = this.eventsProvider.on(AddonModFeedbackProvider.FORM_SUBMITTED, (data) => {
 | 
			
		||||
 | 
			
		||||
@ -68,12 +68,12 @@ export class AddonModQuizIndexComponent extends CoreCourseModuleMainActivityComp
 | 
			
		||||
    protected finishedObserver: any; // It will observe attempt finished events.
 | 
			
		||||
    protected hasPlayed = false; // Whether the user has gone to the quiz player (attempted).
 | 
			
		||||
 | 
			
		||||
    constructor(injector: Injector, protected quizProvider: AddonModQuizProvider, @Optional() protected content: Content,
 | 
			
		||||
    constructor(injector: Injector, protected quizProvider: AddonModQuizProvider, @Optional() content: Content,
 | 
			
		||||
            protected quizHelper: AddonModQuizHelperProvider, protected quizOffline: AddonModQuizOfflineProvider,
 | 
			
		||||
            protected quizSync: AddonModQuizSyncProvider, protected behaviourDelegate: CoreQuestionBehaviourDelegate,
 | 
			
		||||
            protected prefetchHandler: AddonModQuizPrefetchHandler, protected navCtrl: NavController,
 | 
			
		||||
            protected prefetchDelegate: CoreCourseModulePrefetchDelegate) {
 | 
			
		||||
        super(injector);
 | 
			
		||||
        super(injector, content);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -38,10 +38,10 @@ export class AddonModSurveyIndexComponent extends CoreCourseModuleMainActivityCo
 | 
			
		||||
    protected userId: number;
 | 
			
		||||
    protected syncEventName = AddonModSurveySyncProvider.AUTO_SYNCED;
 | 
			
		||||
 | 
			
		||||
    constructor(injector: Injector, private surveyProvider: AddonModSurveyProvider, @Optional() private content: Content,
 | 
			
		||||
    constructor(injector: Injector, private surveyProvider: AddonModSurveyProvider, @Optional() content: Content,
 | 
			
		||||
            private surveyHelper: AddonModSurveyHelperProvider, private surveyOffline: AddonModSurveyOfflineProvider,
 | 
			
		||||
            private surveySync: AddonModSurveySyncProvider) {
 | 
			
		||||
        super(injector);
 | 
			
		||||
        super(injector, content);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -83,8 +83,6 @@ export class AddonModSurveyIndexComponent extends CoreCourseModuleMainActivityCo
 | 
			
		||||
     */
 | 
			
		||||
    protected isRefreshSyncNeeded(syncEventData: any): boolean {
 | 
			
		||||
        if (this.survey && syncEventData.surveyId == this.survey.id && syncEventData.userId == this.userId) {
 | 
			
		||||
            this.content.scrollToTop();
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -189,9 +187,7 @@ export class AddonModSurveyIndexComponent extends CoreCourseModuleMainActivityCo
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return this.surveyProvider.submitAnswers(this.survey.id, this.survey.name, this.courseId, answers).then(() => {
 | 
			
		||||
                this.content.scrollToTop();
 | 
			
		||||
 | 
			
		||||
                return this.refreshContent(false);
 | 
			
		||||
                return this.showLoadingAndRefresh(false);
 | 
			
		||||
            }).finally(() => {
 | 
			
		||||
                modal.dismiss();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
@ -50,6 +50,7 @@ export class AddonModSurveyModuleHandler implements CoreCourseModuleHandler {
 | 
			
		||||
            icon: this.courseProvider.getModuleIconSrc('survey'),
 | 
			
		||||
            title: module.name,
 | 
			
		||||
            class: 'addon-mod_survey-handler',
 | 
			
		||||
            showDownloadButton: true,
 | 
			
		||||
            action(event: Event, navCtrl: NavController, module: any, courseId: number, options: NavOptions): void {
 | 
			
		||||
                navCtrl.push('AddonModSurveyIndexPage', {module: module, courseId: courseId}, options);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -636,6 +636,11 @@ canvas[core-chart] {
 | 
			
		||||
    background-image: url("data:image/svg+xml;charset=utf-8,<svg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2012%2020'><path%20d='M2,20l-2-2l8-8L0,2l2-2l10,10L2,20z'%20fill='%23FFFFFF'/></svg>") !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// For list where some items have detail icon and some others don't.
 | 
			
		||||
.core-list-align-detail-right .item .item-inner {
 | 
			
		||||
    @include padding-horizontal(null, 32px);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[ion-fixed] {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -13,6 +13,7 @@
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
 | 
			
		||||
import { Injector } from '@angular/core';
 | 
			
		||||
import { Content } from 'ionic-angular';
 | 
			
		||||
import { CoreSitesProvider } from '@providers/sites';
 | 
			
		||||
import { CoreCourseProvider } from '@core/course/providers/course';
 | 
			
		||||
import { CoreCourseModulePrefetchDelegate } from '@core/course/providers/module-prefetch-delegate';
 | 
			
		||||
@ -47,7 +48,7 @@ export class CoreCourseModuleMainActivityComponent extends CoreCourseModuleMainR
 | 
			
		||||
    protected eventsProvider: CoreEventsProvider;
 | 
			
		||||
    protected modulePrefetchProvider: CoreCourseModulePrefetchDelegate;
 | 
			
		||||
 | 
			
		||||
    constructor(injector: Injector) {
 | 
			
		||||
    constructor(injector: Injector, protected content?: Content) {
 | 
			
		||||
        super(injector);
 | 
			
		||||
 | 
			
		||||
        this.sitesProvider = injector.get(CoreSitesProvider);
 | 
			
		||||
@ -118,10 +119,8 @@ export class CoreCourseModuleMainActivityComponent extends CoreCourseModuleMainR
 | 
			
		||||
     */
 | 
			
		||||
    protected autoSyncEventReceived(syncEventData: any): void {
 | 
			
		||||
        if (this.isRefreshSyncNeeded(syncEventData)) {
 | 
			
		||||
            this.loaded = false;
 | 
			
		||||
 | 
			
		||||
            // Refresh the data.
 | 
			
		||||
            this.refreshContent(false);
 | 
			
		||||
            this.showLoadingAndRefresh(false);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -146,6 +145,22 @@ export class CoreCourseModuleMainActivityComponent extends CoreCourseModuleMainR
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Show loading and perform the refresh content function.
 | 
			
		||||
     *
 | 
			
		||||
     * @param  {boolean}      [sync=false]       If the refresh needs syncing.
 | 
			
		||||
     * @param  {boolean}      [showErrors=false] Wether to show errors to the user or hide them.
 | 
			
		||||
     * @return {Promise<any>} Resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    protected showLoadingAndRefresh(sync: boolean = false, showErrors: boolean = false): Promise<any> {
 | 
			
		||||
        this.refreshIcon = 'spinner';
 | 
			
		||||
        this.syncIcon = 'spinner';
 | 
			
		||||
        this.loaded = false;
 | 
			
		||||
        this.content && this.content.scrollToTop();
 | 
			
		||||
 | 
			
		||||
        return this.refreshContent(true, showErrors);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Download the component contents.
 | 
			
		||||
     *
 | 
			
		||||
 | 
			
		||||
@ -11,4 +11,8 @@
 | 
			
		||||
</ion-header>
 | 
			
		||||
<ion-content padding>
 | 
			
		||||
    <core-format-text [text]="content" [component]="component" [componentId]="componentId"></core-format-text>
 | 
			
		||||
 | 
			
		||||
    <ion-card *ngIf="files && files.length">
 | 
			
		||||
        <core-file *ngFor="let file of files" [file]="file" [component]="component" [componentId]="componentId"></core-file>
 | 
			
		||||
    </ion-card>
 | 
			
		||||
</ion-content>
 | 
			
		||||
 | 
			
		||||
@ -16,6 +16,7 @@ import { NgModule } from '@angular/core';
 | 
			
		||||
import { IonicPageModule } from 'ionic-angular';
 | 
			
		||||
import { TranslateModule } from '@ngx-translate/core';
 | 
			
		||||
import { CoreViewerTextPage } from './text';
 | 
			
		||||
import { CoreComponentsModule } from '@components/components.module';
 | 
			
		||||
import { CoreDirectivesModule } from '@directives/directives.module';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@ -26,6 +27,7 @@ import { CoreDirectivesModule } from '@directives/directives.module';
 | 
			
		||||
        CoreViewerTextPage
 | 
			
		||||
    ],
 | 
			
		||||
    imports: [
 | 
			
		||||
        CoreComponentsModule,
 | 
			
		||||
        CoreDirectivesModule,
 | 
			
		||||
        IonicPageModule.forChild(CoreViewerTextPage),
 | 
			
		||||
        TranslateModule.forChild()
 | 
			
		||||
 | 
			
		||||
@ -29,12 +29,14 @@ export class CoreViewerTextPage {
 | 
			
		||||
    content: string; // Page content.
 | 
			
		||||
    component: string; // Component to use in format-text.
 | 
			
		||||
    componentId: string | number; // Component ID to use in format-text.
 | 
			
		||||
    files: any[]; // List of files.
 | 
			
		||||
 | 
			
		||||
    constructor(private viewCtrl: ViewController, params: NavParams, textUtils: CoreTextUtilsProvider) {
 | 
			
		||||
        this.title = params.get('title');
 | 
			
		||||
        this.content = params.get('content');
 | 
			
		||||
        this.component = params.get('component');
 | 
			
		||||
        this.componentId = params.get('componentId');
 | 
			
		||||
        this.files = params.get('files');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -211,6 +211,11 @@ export class CoreFormatTextDirective implements OnChanges {
 | 
			
		||||
                    this.element.style.maxHeight = this.maxHeight + 'px';
 | 
			
		||||
 | 
			
		||||
                    this.element.addEventListener('click', (e) => {
 | 
			
		||||
                        if (e.defaultPrevented) {
 | 
			
		||||
                            // Ignore it if the event was prevented by some other listener.
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        e.preventDefault();
 | 
			
		||||
                        e.stopPropagation();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -303,14 +303,16 @@ export class CoreTextUtilsProvider {
 | 
			
		||||
     * @param {string} text Content of the text to be expanded.
 | 
			
		||||
     * @param {string} [component] Component to link the embedded files to.
 | 
			
		||||
     * @param {string|number} [componentId] An ID to use in conjunction with the component.
 | 
			
		||||
     * @param {any[]} [files] List of files to display along with the text.
 | 
			
		||||
     */
 | 
			
		||||
    expandText(title: string, text: string, component?: string, componentId?: string | number): void {
 | 
			
		||||
    expandText(title: string, text: string, component?: string, componentId?: string | number, files?: any[]): void {
 | 
			
		||||
        if (text.length > 0) {
 | 
			
		||||
            const params: any = {
 | 
			
		||||
                title: title,
 | 
			
		||||
                content: text,
 | 
			
		||||
                component: component,
 | 
			
		||||
                componentId: componentId
 | 
			
		||||
                componentId: componentId,
 | 
			
		||||
                files: files
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            // Open a modal with the contents.
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user