MOBILE-2354 workshop: Index page
parent
3652d0591d
commit
0591c35a0b
|
@ -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 { AddonModWorkshopIndexComponent } from './index/index';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AddonModWorkshopIndexComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
IonicModule,
|
||||
TranslateModule.forChild(),
|
||||
CoreComponentsModule,
|
||||
CoreDirectivesModule,
|
||||
CoreCourseComponentsModule
|
||||
],
|
||||
providers: [
|
||||
],
|
||||
exports: [
|
||||
AddonModWorkshopIndexComponent
|
||||
],
|
||||
entryComponents: [
|
||||
AddonModWorkshopIndexComponent
|
||||
]
|
||||
})
|
||||
export class AddonModWorkshopComponentsModule {}
|
|
@ -0,0 +1,176 @@
|
|||
<!-- 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="description" [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">
|
||||
<core-course-module-description *ngIf="description && selectedPhase == workshopPhases.PHASE_SETUP" [description]="description" [component]="component" [componentId]="componentId"></core-course-module-description>
|
||||
|
||||
<ion-card *ngIf="phases">
|
||||
<ion-item (click)="selectPhase()">
|
||||
<h2 stacked text-wrap>{{ phases[selectedPhase].title }}</h2>
|
||||
<p text-wrap *ngIf="phases[selectedPhase].code == workshop.phase">{{ 'addon.mod_workshop.userplancurrentphase' | translate }}</p>
|
||||
<ion-icon item-end name="arrow-dropdown"></ion-icon>
|
||||
</ion-item>
|
||||
<a ion-item text-wrap *ngIf="phases[selectedPhase].switchUrl" [href]="phases[selectedPhase].switchUrl" detail-none>
|
||||
<ion-icon item-start name="swap"></ion-icon>
|
||||
{{ 'addon.mod_workshop.switchphase' + selectedPhase | translate }}
|
||||
<ion-icon item-end name="open"></ion-icon>
|
||||
</a>
|
||||
</ion-card>
|
||||
|
||||
<ion-card *ngIf="phases && phases[selectedPhase] && phases[selectedPhase].tasks.length">
|
||||
<ion-item text-wrap *ngFor="let task of phases[selectedPhase].tasks" [ngClass]="{'item-dimmed': selectedPhase != workshop.phase}" (click)="runTask(task)" detail-none>
|
||||
<ion-icon item-start name="radio-button-off" *ngIf="task.completed == null"></ion-icon>
|
||||
<ion-icon item-start name="close-circle" color="danger" *ngIf="task.completed == ''"></ion-icon>
|
||||
<ion-icon item-start name="information-circle" color="info" *ngIf="task.completed == 'info'"></ion-icon>
|
||||
<ion-icon item-start name="checkmark-circle" color="success" *ngIf="task.completed == '1'"></ion-icon>
|
||||
|
||||
<h2>{{task.title}}</h2>
|
||||
<p *ngIf="task.details"><core-format-text [text]="task.details"></core-format-text></p>
|
||||
<ion-icon item-end *ngIf="task.link && !task.support" name="open"></ion-icon>
|
||||
</ion-item>
|
||||
</ion-card>
|
||||
|
||||
<!-- Has something offline. -->
|
||||
<div class="core-warning-card" icon-start *ngIf="hasOffline">
|
||||
<ion-icon name="warning"></ion-icon>
|
||||
{{ 'core.hasdatatosync' | translate: {$a: moduleName} }}
|
||||
</div>
|
||||
|
||||
<div *ngIf="access && workshop && workshop.phase >= selectedPhase">
|
||||
<!-- SUBMISSION PHASE -->
|
||||
<ng-container *ngIf="selectedPhase == workshopPhases.PHASE_SUBMISSION">
|
||||
<ion-card *ngIf="workshop.instructauthors">
|
||||
<ion-item text-wrap>
|
||||
<h2>{{ 'addon.mod_workshop.areainstructauthors' | translate }}</h2>
|
||||
<core-format-text fullOnClick="true" [component]="component" [componentId]="workshop.cmid" [text]="workshop.instructauthors"></core-format-text>
|
||||
</ion-item>
|
||||
</ion-card>
|
||||
|
||||
<ion-card *ngIf="canSubmit">
|
||||
<ion-item text-wrap *ngIf="!submission">
|
||||
<h2>{{ 'addon.mod_workshop.yoursubmission' | translate }}</h2>
|
||||
<p>{{ 'addon.mod_workshop.noyoursubmission' | translate }}</p>
|
||||
</ion-item>
|
||||
|
||||
<!-- <addon-mod-workshop-submission *ngIf="submission" [submission]="submission" [courseId]="workshop.course" [module]="module" [workshop]="workshop" [access]="access"></addon-mod-workshop-submission> -->
|
||||
</ion-card>
|
||||
|
||||
<!-- Show only on current phase -->
|
||||
<ng-container *ngIf="workshop.phase == selectedPhase">
|
||||
<ion-item text-wrap *ngIf="canSubmit && ((access.creatingsubmissionallowed && !submission) || (access.modifyingsubmissionallowed && submission))">
|
||||
<button ion-button icon-start block *ngIf="access.creatingsubmissionallowed && !submission" (click)="runTaskByCode('submit')">
|
||||
<ion-icon name="add"></ion-icon>
|
||||
{{ 'addon.mod_workshop.createsubmission' | translate }}
|
||||
</button>
|
||||
<button ion-button icon-start block *ngIf="access.modifyingsubmissionallowed && submission" (click)="runTaskByCode('submit')">
|
||||
<ion-icon name="create"></ion-icon>
|
||||
{{ 'addon.mod_workshop.editsubmission' | translate }}
|
||||
</button>
|
||||
</ion-item>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
<!-- ASSESSMENT PHASE -->
|
||||
<ng-container *ngIf="selectedPhase == workshopPhases.PHASE_ASSESSMENT">
|
||||
<ion-card *ngIf="workshop.instructreviewers">
|
||||
<ion-item text-wrap>
|
||||
<h2>{{ 'addon.mod_workshop.areainstructreviewers' | translate }}</h2>
|
||||
<core-format-text fullOnClick="true" [component]="component" [componentId]="workshop.cmid" [text]="workshop.instructreviewers"></core-format-text>
|
||||
</ion-item>
|
||||
</ion-card>
|
||||
|
||||
<ion-card *ngIf="canAssess && assessments.length">
|
||||
<ion-item text-wrap>
|
||||
<h2>{{ 'addon.mod_workshop.assignedassessments' | translate }}</h2>
|
||||
</ion-item>
|
||||
<!-- <addon-mod-workshop-submission *ngFor="let assessment of assessments" [submission]="assessment.submission" [assessment]="assessment" [courseId]="workshop.course" [module]="module" [workshop]="workshop" [access]="access" summary="true"></addon-mod-workshop-submission> -->
|
||||
</ion-card >
|
||||
</ng-container>
|
||||
|
||||
<ion-card *ngIf="!access.canviewallsubmissions && selectedPhase == workshop.phase && (canSubmit || canAssess) && selectedPhase == workshopPhases.PHASE_EVALUATION">
|
||||
<ion-item text-wrap *ngIf="submission" (click)="switchPhase(workshopPhases.PHASE_SUBMISSION)" detail-push>
|
||||
<h2>{{ 'addon.mod_workshop.yoursubmission' | translate }}</h2>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="canAssess" (click)="switchPhase(workshopPhases.PHASE_ASSESSMENT)" detail-push>
|
||||
<h2>{{ 'addon.mod_workshop.assignedassessments' | translate }}</h2>
|
||||
</ion-item>
|
||||
</ion-card>
|
||||
|
||||
<!-- CLOSED PHASE -->
|
||||
<ng-container *ngIf="selectedPhase == workshopPhases.PHASE_CLOSED">
|
||||
<ion-card *ngIf="workshop.conclusion">
|
||||
<ion-item text-wrap>
|
||||
<h2>{{ 'addon.mod_workshop.conclusion' | translate }}</h2>
|
||||
<core-format-text fullOnClick="true" [component]="component" [componentId]="workshop.cmid" [text]="workshop.conclusion"></core-format-text>
|
||||
</ion-item>
|
||||
</ion-card>
|
||||
|
||||
<ion-card *ngIf="userGrades">
|
||||
<ion-item-divider color="light" text-wrap>
|
||||
<h2>{{ 'addon.mod_workshop.yourgrades' | translate }}</h2>
|
||||
</ion-item-divider>
|
||||
<ion-item text-wrap *ngIf="userGrades.submissionlongstrgrade" (click)="switchPhase(workshopPhases.PHASE_SUBMISSION)" detail-push>
|
||||
<h2>{{ 'addon.mod_workshop.submissiongrade' | translate }}</h2>
|
||||
<core-format-text [text]="userGrades.submissionlongstrgrade"></core-format-text>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="userGrades.assessmentlongstrgrade" (click)="switchPhase(workshopPhases.PHASE_ASSESSMENT)" detail-push>
|
||||
<h2>{{ 'addon.mod_workshop.gradinggrade' | translate }}</h2>
|
||||
<core-format-text [text]="userGrades.assessmentlongstrgrade"></core-format-text>
|
||||
</ion-item>
|
||||
</ion-card>
|
||||
|
||||
<ion-card *ngIf="publishedSubmissions.length">
|
||||
<ion-item text-wrap>
|
||||
<h2>{{ 'addon.mod_workshop.publishedsubmissions' | translate }}</h2>
|
||||
</ion-item>
|
||||
<!-- <addon-mod-workshop-submission *ngFor="let submission of publishedSubmissions" [submission]="submission" [courseId]="workshop.course" [module]="module" [workshop]="workshop" [access]="access" summary="true"></addon-mod-workshop-submission> -->
|
||||
</ion-card>
|
||||
</ng-container>
|
||||
|
||||
<!-- MULTIPLE PHASES SUBMISSION OR GREATER only teachers -->
|
||||
<ion-card *ngIf="workshop.phase == selectedPhase && access.canviewallsubmissions && selectedPhase >= workshopPhases.PHASE_SUBMISSION && grades.length">
|
||||
<ion-item text-wrap *ngIf="selectedPhase == workshopPhases.PHASE_SUBMISSION">
|
||||
<h2>{{ 'addon.mod_workshop.submissionsreport' | translate }}</h2>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="selectedPhase > workshopPhases.PHASE_SUBMISSION">
|
||||
<h2>{{ 'addon.mod_workshop.gradesreport' | translate }}</h2>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="groupInfo && (groupInfo.separateGroups || groupInfo.visibleGroups)">
|
||||
<ion-label id="addon-workshop-groupslabel" *ngIf="groupInfo.separateGroups">{{ 'core.groupsseparate' | translate }}</ion-label>
|
||||
<ion-label id="addon-workshop-groupslabel" *ngIf="groupInfo.visibleGroups">{{ 'core.groupsvisible' | translate }}</ion-label>
|
||||
<ion-select [(ngModel)]="selectedGroup" (ionChange)="setGroup(selectedGroup)" aria-labelledby="addon-workshop-groupslabel">
|
||||
<ion-option *ngFor="let groupOpt of groupInfo.groups" [value]="groupOpt.id">{{groupOpt.name}}</ion-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
|
||||
<!-- <addon-mod-workshop-submission *ngFor="submission of grades" [submission]="submission" [courseId]="workshop.course" [module]="module" [workshop]="workshop" [access]="access" summary="true"></addon-mod-workshop-submission>-->
|
||||
|
||||
<ion-grid ngIf="page > 0 || hasNextPage">
|
||||
<ion-row align-items-center>
|
||||
<ion-col *ngIf="page > 0">
|
||||
<button ion-button block outline icon-start (click)="gotoSubmissionsPage(page - 1)">>
|
||||
<ion-icon name="arrow-back"></ion-icon>
|
||||
{{ 'core.previous' | translate }}
|
||||
</button>
|
||||
</ion-col>
|
||||
<ion-col *ngIf="hasNextPage">
|
||||
<button ion-button block icon-end click)="gotoSubmissionsPage(page + 1)">
|
||||
{{ 'core.next' | translate }}
|
||||
<ion-icon name="arrow-forward"></ion-icon>
|
||||
</button>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</ion-card>
|
||||
</div>
|
||||
</core-loading>
|
|
@ -0,0 +1,485 @@
|
|||
// (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, Input, Optional, Injector } from '@angular/core';
|
||||
import { Content, ModalController, NavController, Platform } from 'ionic-angular';
|
||||
import { CoreGroupInfo, CoreGroupsProvider } from '@providers/groups';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreCourseModuleMainActivityComponent } from '@core/course/classes/main-activity-component';
|
||||
import { AddonModWorkshopProvider } from '../../providers/workshop';
|
||||
import { AddonModWorkshopHelperProvider } from '../../providers/helper';
|
||||
import { AddonModWorkshopSyncProvider } from '../../providers/sync';
|
||||
import { AddonModWorkshopOfflineProvider } from '../../providers/offline';
|
||||
|
||||
/**
|
||||
* Component that displays a workshop index page.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'addon-mod-workshop-index',
|
||||
templateUrl: 'index.html',
|
||||
})
|
||||
export class AddonModWorkshopIndexComponent extends CoreCourseModuleMainActivityComponent {
|
||||
@Input() group = 0;
|
||||
|
||||
moduleName = 'workshop';
|
||||
workshop: any;
|
||||
page = 0;
|
||||
access: any;
|
||||
phases: any;
|
||||
grades: any;
|
||||
assessments: any;
|
||||
userGrades: any;
|
||||
publishedSubmissions: any;
|
||||
selectedPhase: number;
|
||||
submission: any;
|
||||
groupInfo: CoreGroupInfo = {
|
||||
groups: [],
|
||||
separateGroups: false,
|
||||
visibleGroups: false
|
||||
};
|
||||
canSubmit = false;
|
||||
canAssess = false;
|
||||
hasNextPage = false;
|
||||
|
||||
workshopPhases = {
|
||||
PHASE_SETUP: AddonModWorkshopProvider.PHASE_SETUP,
|
||||
PHASE_SUBMISSION: AddonModWorkshopProvider.PHASE_SUBMISSION,
|
||||
PHASE_ASSESSMENT: AddonModWorkshopProvider.PHASE_ASSESSMENT,
|
||||
PHASE_EVALUATION: AddonModWorkshopProvider.PHASE_EVALUATION,
|
||||
PHASE_CLOSED: AddonModWorkshopProvider.PHASE_CLOSED
|
||||
};
|
||||
|
||||
protected offlineSubmissions = [];
|
||||
protected supportedTasks = { // Add here native supported tasks.
|
||||
submit: true
|
||||
};
|
||||
protected obsSubmissionChanged: any;
|
||||
protected obsAssessmentSaved: any;
|
||||
protected appResumeSubscription: any;
|
||||
|
||||
constructor(injector: Injector, private workshopProvider: AddonModWorkshopProvider, @Optional() content: Content,
|
||||
private workshopOffline: AddonModWorkshopOfflineProvider, private groupsProvider: CoreGroupsProvider,
|
||||
private navCtrl: NavController, private modalCtrl: ModalController, private utils: CoreUtilsProvider,
|
||||
platform: Platform, private workshopHelper: AddonModWorkshopHelperProvider,
|
||||
private workshopSync: AddonModWorkshopSyncProvider) {
|
||||
super(injector, content);
|
||||
|
||||
// Listen to submission and assessment changes.
|
||||
this.obsSubmissionChanged = this.eventsProvider.on(AddonModWorkshopProvider.SUBMISSION_CHANGED, (data) => {
|
||||
this.eventReceived(data);
|
||||
}, this.siteId);
|
||||
|
||||
// Listen to submission and assessment changes.
|
||||
this.obsAssessmentSaved = this.eventsProvider.on(AddonModWorkshopProvider.ASSESSMENT_SAVED, (data) => {
|
||||
this.eventReceived(data);
|
||||
}, this.siteId);
|
||||
|
||||
// Since most actions will take the user out of the app, we should refresh the view when the app is resumed.
|
||||
this.appResumeSubscription = platform.resume.subscribe(() => {
|
||||
this.content && this.content.scrollToTop();
|
||||
|
||||
this.loaded = false;
|
||||
this.refreshContent(true, false);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Component being initialized.
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
super.ngOnInit();
|
||||
|
||||
this.loadContent(false, true).then(() => {
|
||||
if (!this.workshop) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.workshopProvider.logView(this.workshop.id).then(() => {
|
||||
this.courseProvider.checkModuleCompletion(this.courseId, this.module.completionstatus);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Function called when we receive an event of submission changes.
|
||||
*
|
||||
* @param {any} data Data received by the event.
|
||||
*/
|
||||
protected eventReceived(data: any): void {
|
||||
if ((this.workshop && this.workshop.id === data.workshopid) || data.cmid === module.id) {
|
||||
this.content && this.content.scrollToTop();
|
||||
|
||||
this.loaded = false;
|
||||
this.refreshContent(true, false);
|
||||
// Check completion since it could be configured to complete once the user adds a new discussion or replies.
|
||||
this.courseProvider.checkModuleCompletion(this.courseId, this.module.completionstatus);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the invalidate content function.
|
||||
*
|
||||
* @return {Promise<any>} Resolved when done.
|
||||
*/
|
||||
protected invalidateContent(): Promise<any> {
|
||||
const promises = [];
|
||||
|
||||
promises.push(this.workshopProvider.invalidateWorkshopData(this.courseId));
|
||||
if (this.workshop) {
|
||||
promises.push(this.workshopProvider.invalidateWorkshopAccessInformationData(this.workshop.id));
|
||||
promises.push(this.workshopProvider.invalidateUserPlanPhasesData(this.workshop.id));
|
||||
if (this.canSubmit) {
|
||||
promises.push(this.workshopProvider.invalidateSubmissionsData(this.workshop.id));
|
||||
}
|
||||
if (this.access.canviewallsubmissions) {
|
||||
promises.push(this.workshopProvider.invalidateGradeReportData(this.workshop.id));
|
||||
promises.push(this.groupsProvider.invalidateActivityAllowedGroups(this.workshop.coursemodule));
|
||||
promises.push(this.groupsProvider.invalidateActivityGroupMode(this.workshop.coursemodule));
|
||||
}
|
||||
if (this.canAssess) {
|
||||
promises.push(this.workshopProvider.invalidateReviewerAssesmentsData(this.workshop.id));
|
||||
}
|
||||
promises.push(this.workshopProvider.invalidateGradesData(this.workshop.id));
|
||||
}
|
||||
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.workshop && syncEventData.workshopId == this.workshop.id) {
|
||||
// Refresh the data.
|
||||
this.content.scrollToTop();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Download feedback contents.
|
||||
*
|
||||
* @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> {
|
||||
return this.workshopProvider.getWorkshop(this.courseId, this.module.id).then((workshop) => {
|
||||
this.workshop = workshop;
|
||||
|
||||
this.selectedPhase = workshop.phase;
|
||||
|
||||
this.description = workshop.intro || workshop.description;
|
||||
this.dataRetrieved.emit(workshop);
|
||||
|
||||
if (sync) {
|
||||
// Try to synchronize the feedback.
|
||||
return this.syncActivity(showErrors);
|
||||
}
|
||||
}).then(() => {
|
||||
// Check if there are answers stored in offline.
|
||||
return this.workshopProvider.getWorkshopAccessInformation(this.workshop.id);
|
||||
}).then((accessData) => {
|
||||
this.access = accessData;
|
||||
|
||||
if (accessData.canviewallsubmissions) {
|
||||
return this.groupsProvider.getActivityGroupInfo(this.workshop.coursemodule,
|
||||
accessData.canviewallsubmissions).then((groupInfo) => {
|
||||
this.groupInfo = groupInfo;
|
||||
|
||||
// Check selected group is accessible.
|
||||
if (groupInfo && groupInfo.groups && groupInfo.groups.length > 0) {
|
||||
const found = groupInfo.groups.some((group) => {
|
||||
return group.id == this.group;
|
||||
});
|
||||
if (!found) {
|
||||
this.group = groupInfo.groups[0].id;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
}).then(() => {
|
||||
return this.workshopProvider.getUserPlanPhases(this.workshop.id);
|
||||
}).then((phases) => {
|
||||
this.phases = phases;
|
||||
|
||||
// Treat phases.
|
||||
for (const x in phases) {
|
||||
phases[x].tasks.forEach((task) => {
|
||||
if (!task.link && (task.code == 'examples' || task.code == 'prepareexamples')) {
|
||||
// Add links to manage examples.
|
||||
task.link = this.externalUrl;
|
||||
} else if (task.link && typeof this.supportedTasks[task.code] !== 'undefined') {
|
||||
task.support = true;
|
||||
}
|
||||
});
|
||||
const action = phases[x].actions.find((action) => {
|
||||
return action.url && action.type == 'switchphase';
|
||||
});
|
||||
phases[x].switchUrl = action ? action.url : '';
|
||||
}
|
||||
|
||||
// Check if there are info stored in offline.
|
||||
return this.workshopOffline.hasWorkshopOfflineData(this.workshop.id).then((hasOffline) => {
|
||||
this.hasOffline = hasOffline;
|
||||
if (hasOffline) {
|
||||
return this.workshopOffline.getSubmissions(this.workshop.id).then((submissionsActions) => {
|
||||
this.offlineSubmissions = submissionsActions;
|
||||
});
|
||||
} else {
|
||||
this.offlineSubmissions = [];
|
||||
}
|
||||
});
|
||||
}).then(() => {
|
||||
return this.setPhaseInfo();
|
||||
}).then(() => {
|
||||
// All data obtained, now fill the context menu.
|
||||
this.fillContextMenu(refresh);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves and shows submissions grade page.
|
||||
*
|
||||
* @param {number} page Page number to be retrieved.
|
||||
* @return {Promise<any>} Resolved when done.
|
||||
*/
|
||||
gotoSubmissionsPage(page: number): Promise<any> {
|
||||
return this.workshopProvider.getGradesReport(this.workshop.id, this.group, page).then((report) => {
|
||||
const numEntries = (report && report.grades && report.grades.length) || 0;
|
||||
|
||||
this.page = page;
|
||||
|
||||
this.hasNextPage = numEntries >= AddonModWorkshopProvider.PER_PAGE && ((this.page + 1) *
|
||||
AddonModWorkshopProvider.PER_PAGE) < report.totalcount;
|
||||
|
||||
this.grades = report.grades || [];
|
||||
|
||||
this.grades.forEach((submission) => {
|
||||
const actions = this.workshopHelper.filterSubmissionActions(this.offlineSubmissions, submission.submissionid
|
||||
|| false);
|
||||
submission = this.workshopHelper.applyOfflineData(submission, actions);
|
||||
|
||||
return this.workshopHelper.applyOfflineData(submission, actions).then((offlineSubmission) => {
|
||||
submission = offlineSubmission;
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Open task.
|
||||
*
|
||||
* @param {any} task Task to be done.
|
||||
*/
|
||||
runTask(task: any): void {
|
||||
if (task.support) {
|
||||
if (task.code == 'submit' && this.canSubmit && ((this.access.creatingsubmissionallowed && !this.submission) ||
|
||||
(this.access.modifyingsubmissionallowed && this.submission))) {
|
||||
const params = {
|
||||
module: module,
|
||||
access: this.access,
|
||||
courseId: this.courseId,
|
||||
submission: this.submission
|
||||
};
|
||||
|
||||
if (this.submission.id) {
|
||||
params['submissionId'] = this.submission.id;
|
||||
}
|
||||
|
||||
this.navCtrl.push('AddonModWorkshopEditSubmissionPage', params);
|
||||
}
|
||||
} else if (task.link) {
|
||||
this.utils.openInBrowser(task.link);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run task link on current phase.
|
||||
*
|
||||
* @param {string} taskCode Code related to the task to run.
|
||||
*/
|
||||
runTaskByCode(taskCode: string): void {
|
||||
const task = this.workshopHelper.getTask(this.phases[this.workshop.phase].tasks, taskCode);
|
||||
|
||||
return task ? this.runTask(task) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select Phase to be shown.
|
||||
*/
|
||||
selectPhase(): void {
|
||||
if (this.phases) {
|
||||
const modal = this.modalCtrl.create('AddonModWorkshopPhaseSelectorPage', {
|
||||
phases: this.utils.objectToArray(this.phases),
|
||||
selected: this.selectedPhase,
|
||||
workshopPhase: this.workshop.phase
|
||||
});
|
||||
modal.onDidDismiss((phase) => {
|
||||
// Add data to search object.
|
||||
typeof phase != 'undefined' && this.switchPhase(phase);
|
||||
});
|
||||
modal.present();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set group to see the workshop.
|
||||
* @param {number} groupId Group Id.
|
||||
* @return {Promise<any>} Promise resolved when done.
|
||||
*/
|
||||
setGroup(groupId: number): Promise<any> {
|
||||
this.group = groupId;
|
||||
|
||||
return this.gotoSubmissionsPage(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to set current phase information.
|
||||
*
|
||||
* @return {Promise<any>} Promise resolved when done.
|
||||
*/
|
||||
protected setPhaseInfo(): Promise<any> {
|
||||
this.submission = false;
|
||||
this.canAssess = false;
|
||||
this.assessments = false;
|
||||
this.userGrades = false;
|
||||
this.publishedSubmissions = false;
|
||||
|
||||
this.canSubmit = this.workshopHelper.canSubmit(this.workshop, this.access,
|
||||
this.phases[AddonModWorkshopProvider.PHASE_SUBMISSION].tasks);
|
||||
|
||||
const promises = [];
|
||||
|
||||
if (this.canSubmit) {
|
||||
promises.push(this.workshopHelper.getUserSubmission(this.workshop.id).then((submission) => {
|
||||
const actions = this.workshopHelper.filterSubmissionActions(this.offlineSubmissions, submission.id || false);
|
||||
|
||||
return this.workshopHelper.applyOfflineData(submission, actions).then((submission) => {
|
||||
this.submission = submission;
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
if (this.access.canviewallsubmissions && this.workshop.phase >= AddonModWorkshopProvider.PHASE_SUBMISSION) {
|
||||
promises.push(this.gotoSubmissionsPage(this.page));
|
||||
}
|
||||
|
||||
let assessPromise = Promise.resolve();
|
||||
|
||||
if (this.workshop.phase >= AddonModWorkshopProvider.PHASE_ASSESSMENT) {
|
||||
this.canAssess = this.workshopHelper.canAssess(this.workshop, this.access);
|
||||
if (this.canAssess) {
|
||||
assessPromise = this.workshopHelper.getReviewerAssessments(this.workshop.id).then((assessments) => {
|
||||
const p2 = [];
|
||||
|
||||
assessments.forEach((assessment) => {
|
||||
assessment.strategy = this.workshop.strategy;
|
||||
if (this.hasOffline) {
|
||||
p2.push(this.workshopOffline.getAssessment(this.workshop.id, assessment.id)
|
||||
.then((offlineAssessment) => {
|
||||
assessment.offline = true;
|
||||
assessment.timemodified = Math.floor(offlineAssessment.timemodified / 1000);
|
||||
}).catch(() => {
|
||||
// Ignore errors.
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
return Promise.all(p2).then(() => {
|
||||
this.assessments = assessments;
|
||||
});
|
||||
});
|
||||
promises.push(assessPromise);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.workshop.phase == AddonModWorkshopProvider.PHASE_CLOSED) {
|
||||
promises.push(this.workshopProvider.getGrades(this.workshop.id).then((grades) => {
|
||||
this.userGrades = grades.submissionlongstrgrade || grades.assessmentlongstrgrade ? grades : false;
|
||||
}));
|
||||
|
||||
if (this.access.canviewpublishedsubmissions) {
|
||||
promises.push(assessPromise.then(() => {
|
||||
return this.workshopProvider.getSubmissions(this.workshop.id).then((submissions) => {
|
||||
this.publishedSubmissions = submissions.filter((submission) => {
|
||||
if (submission.published) {
|
||||
this.assessments.forEach((assessment) => {
|
||||
submission.reviewedby = [];
|
||||
if (assessment.submissionid == submission.id) {
|
||||
submission.reviewedby.push(this.workshopHelper.realGradeValue(this.workshop, assessment));
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
});
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch shown phase.
|
||||
*
|
||||
* @param {number} phase Selected phase.
|
||||
*/
|
||||
switchPhase(phase: number): void {
|
||||
this.selectedPhase = phase;
|
||||
this.page = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the sync of the activity.
|
||||
*
|
||||
* @return {Promise<any>} Promise resolved when done.
|
||||
*/
|
||||
protected sync(): Promise<any> {
|
||||
return this.workshopSync.syncWorkshop(this.workshop.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if sync has succeed from result sync data.
|
||||
*
|
||||
* @param {any} result Data returned on the sync function.
|
||||
* @return {boolean} If suceed or not.
|
||||
*/
|
||||
protected hasSyncSucceed(result: any): boolean {
|
||||
return result.updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Component being destroyed.
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
super.ngOnDestroy();
|
||||
this.obsSubmissionChanged && this.obsSubmissionChanged.off();
|
||||
this.obsAssessmentSaved && this.obsAssessmentSaved.off();
|
||||
this.appResumeSubscription && this.appResumeSubscription.unsubscribe();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
{
|
||||
"alreadygraded": "Already graded",
|
||||
"areainstructauthors": "Instructions for submission",
|
||||
"areainstructreviewers": "Instructions for assessment",
|
||||
"assess": "Assess",
|
||||
"assessedsubmission": "Assessed submission",
|
||||
"assessmentform": "Assessment form",
|
||||
"assessmentsettings": "Assessment settings",
|
||||
"assessmentstrategynotsupported": "Assessment strategy {{$a}} not supported",
|
||||
"assessmentweight": "Assessment weight",
|
||||
"assignedassessments": "Assigned submissions to assess",
|
||||
"conclusion": "Conclusion",
|
||||
"createsubmission": "Start preparing your submission",
|
||||
"deletesubmission": "Delete submission",
|
||||
"editsubmission": "Edit submission",
|
||||
"feedbackauthor": "Feedback for the author",
|
||||
"feedbackby": "Feedback by {{$a}}",
|
||||
"feedbackreviewer": "Feedback for the reviewer",
|
||||
"givengrades": "Grades given",
|
||||
"gradecalculated": "Calculated grade for submission",
|
||||
"gradeinfo": "Grade: {{$a.received}} of {{$a.max}}",
|
||||
"gradeover": "Override grade for submission",
|
||||
"gradesreport": "Workshop grades report",
|
||||
"gradinggrade": "Grade for assessment",
|
||||
"gradinggradecalculated": "Calculated grade for assessment",
|
||||
"gradinggradeof": "Grade for assessment (of {{$a}})",
|
||||
"gradinggradeover": "Override grade for assessment",
|
||||
"nogradeyet": "No grade yet",
|
||||
"notassessed": "Not assessed yet",
|
||||
"notoverridden": "Not overridden",
|
||||
"noyoursubmission": "You have not submitted your work yet",
|
||||
"overallfeedback": "Overall feedback",
|
||||
"publishedsubmissions": "Published submissions",
|
||||
"publishsubmission": "Publish submission",
|
||||
"publishsubmission_help": "Published submissions are available to the others when the workshop is closed.",
|
||||
"reassess": "Re-assess",
|
||||
"receivedgrades": "Grades received",
|
||||
"selectphase": "Select phase",
|
||||
"submissionattachment": "Attachment",
|
||||
"submissioncontent": "Submission content",
|
||||
"submissiondeleteconfirm": "Are you sure you want to delete the following submission?",
|
||||
"submissiongrade": "Grade for submission",
|
||||
"submissiongradeof": "Grade for submission (of {{$a}})",
|
||||
"submissionrequiredcontent": "You need to enter some text or add a file.",
|
||||
"submissionsreport": "Workshop submissions report",
|
||||
"submissiontitle": "Title",
|
||||
"switchphase10": "Switch to the setup phase",
|
||||
"switchphase20": "Switch to the submission phase",
|
||||
"switchphase30": "Switch to the assessment phase",
|
||||
"switchphase40": "Switch to the evaluation phase",
|
||||
"switchphase50": "Close workshop",
|
||||
"userplancurrentphase": "Current phase",
|
||||
"warningassessmentmodified": "The submission was modified on the site.",
|
||||
"warningsubmissionmodified": "The assessment was modified on the site.",
|
||||
"weightinfo": "Weight: {{$a}}",
|
||||
"yourassessment": "Your assessment",
|
||||
"yourassessmentfor": "Your assessment for {{$a}}",
|
||||
"yourgrades": "Your grades",
|
||||
"yoursubmission": "Your submission"
|
||||
}
|
|
@ -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]="workshopComponent.loaded" (ionRefresh)="workshopComponent.doRefresh($event)">
|
||||
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
||||
</ion-refresher>
|
||||
|
||||
<addon-mod-workshop-index [module]="module" [courseId]="courseId" [group]="selectedGroup" (dataRetrieved)="updateData($event)"></addon-mod-workshop-index>
|
||||
</ion-content>
|
|
@ -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 { AddonModWorkshopComponentsModule } from '../../components/components.module';
|
||||
import { AddonModWorkshopIndexPage } from './index';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AddonModWorkshopIndexPage,
|
||||
],
|
||||
imports: [
|
||||
CoreDirectivesModule,
|
||||
AddonModWorkshopComponentsModule,
|
||||
IonicPageModule.forChild(AddonModWorkshopIndexPage),
|
||||
TranslateModule.forChild()
|
||||
],
|
||||
})
|
||||
export class AddonModWorkshopIndexPageModule {}
|
|
@ -0,0 +1,50 @@
|
|||
// (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 { AddonModWorkshopIndexComponent } from '../../components/index/index';
|
||||
|
||||
/**
|
||||
* Page that displays a workshop.
|
||||
*/
|
||||
@IonicPage({ segment: 'addon-mod-workshop-index' })
|
||||
@Component({
|
||||
selector: 'page-addon-mod-workshop-index',
|
||||
templateUrl: 'index.html',
|
||||
})
|
||||
export class AddonModWorkshopIndexPage {
|
||||
@ViewChild(AddonModWorkshopIndexComponent) workshopComponent: AddonModWorkshopIndexComponent;
|
||||
|
||||
title: string;
|
||||
module: any;
|
||||
courseId: number;
|
||||
selectedGroup: number;
|
||||
|
||||
constructor(navParams: NavParams) {
|
||||
this.module = navParams.get('module') || {};
|
||||
this.courseId = navParams.get('courseId');
|
||||
this.selectedGroup = navParams.get('group') || 0;
|
||||
this.title = this.module.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update some data based on the workshop instance.
|
||||
*
|
||||
* @param {any} workshop Workshop instance.
|
||||
*/
|
||||
updateData(workshop: any): void {
|
||||
this.title = workshop.name || this.title;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title>{{ 'addon.mod_workshop.selectphase' | translate }}</ion-title>
|
||||
<ion-buttons end>
|
||||
<button ion-button icon-only (click)="closeModal()" [attr.aria-label]="'core.close' | translate">
|
||||
<ion-icon name="close"></ion-icon>
|
||||
</button>
|
||||
</ion-buttons>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<ion-list radio-group [(ngModel)]="selected" (ionChange)="switchPhase()">
|
||||
<ng-container *ngFor="let phase of phases">
|
||||
<ion-item *ngIf="workshopPhase >= phase.code || phase.tasks.length || phase.switchUrl">
|
||||
<ion-label>{{ phase.title }}
|
||||
<p text-wrap *ngIf="workshopPhase == phase.code">{{ 'addon.mod_workshop.userplancurrentphase' | translate }}</p>
|
||||
</ion-label>
|
||||
<ion-radio [value]="phase.code"></ion-radio>
|
||||
</ion-item>
|
||||
<ion-item *ngIf="!(workshopPhase >= phase.code || phase.tasks.length || phase.switchUrl)">
|
||||
{{ phase.title }}
|
||||
</ion-item>
|
||||
</ng-container>
|
||||
</ion-list>
|
||||
</ion-content>
|
|
@ -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 { AddonModWorkshopPhaseSelectorPage } from './phase';
|
||||
import { CoreCompileHtmlComponentModule } from '@core/compile/components/compile-html/compile-html.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AddonModWorkshopPhaseSelectorPage,
|
||||
],
|
||||
imports: [
|
||||
CoreDirectivesModule,
|
||||
CoreCompileHtmlComponentModule,
|
||||
IonicPageModule.forChild(AddonModWorkshopPhaseSelectorPage),
|
||||
TranslateModule.forChild()
|
||||
],
|
||||
})
|
||||
export class AddonModWorkshopPhaseSelectorPageModule {}
|
|
@ -0,0 +1,56 @@
|
|||
// (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 } from '@angular/core';
|
||||
import { IonicPage, NavParams, ViewController } from 'ionic-angular';
|
||||
|
||||
/**
|
||||
* Page that displays the phase selector modal.
|
||||
*/
|
||||
@IonicPage({ segment: 'addon-mod-workshop-phase-selector' })
|
||||
@Component({
|
||||
selector: 'page-addon-mod-workshop-phase-selector',
|
||||
templateUrl: 'phase.html',
|
||||
})
|
||||
export class AddonModWorkshopPhaseSelectorPage {
|
||||
selected: number;
|
||||
phases: any;
|
||||
workshopPhase: number;
|
||||
protected original: number;
|
||||
|
||||
constructor(params: NavParams, private viewCtrl: ViewController) {
|
||||
this.selected = params.get('selected');
|
||||
this.original = this.selected;
|
||||
this.phases = params.get('phases');
|
||||
this.workshopPhase = params.get('workshopPhase');
|
||||
}
|
||||
|
||||
/**
|
||||
* Close modal.
|
||||
*/
|
||||
closeModal(): void {
|
||||
this.viewCtrl.dismiss();
|
||||
}
|
||||
|
||||
/**
|
||||
* Select phase.
|
||||
*/
|
||||
switchPhase(): void {
|
||||
// This is a quick hack to avoid the first switch phase call done just when opening the modal.
|
||||
if (this.original != this.selected) {
|
||||
this.viewCtrl.dismiss(this.selected);
|
||||
}
|
||||
this.original = null;
|
||||
}
|
||||
}
|
|
@ -268,7 +268,7 @@ export class AddonModWorkshopHelperProvider {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get a list of stored attachment files for a submission. See $mmaModWorkshopHelper#storeFiles.
|
||||
* Get a list of stored attachment files for a submission. See AddonModWorkshopHelperProvider#storeFiles.
|
||||
*
|
||||
* @param {number} workshopId Workshop ID.
|
||||
* @param {number} submissionId If not editing, it will refer to timecreated.
|
||||
|
@ -286,7 +286,7 @@ export class AddonModWorkshopHelperProvider {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get a list of stored attachment files for a submission and online files also. See $mmaModWorkshopHelper#storeFiles.
|
||||
* Get a list of stored attachment files for a submission and online files also. See AddonModWorkshopHelperProvider#storeFiles.
|
||||
*
|
||||
* @param {any} filesObject Files object combining offline and online information.
|
||||
* @param {number} workshopId Workshop ID.
|
||||
|
@ -355,7 +355,7 @@ export class AddonModWorkshopHelperProvider {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get a list of stored attachment files for an assessment. See $mmaModWorkshopHelper#storeFiles.
|
||||
* Get a list of stored attachment files for an assessment. See AddonModWorkshopHelperProvider#storeFiles.
|
||||
*
|
||||
* @param {number} workshopId Workshop ID.
|
||||
* @param {number} assessmentId Assessment ID.
|
||||
|
@ -372,7 +372,7 @@ export class AddonModWorkshopHelperProvider {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get a list of stored attachment files for an assessment and online files also. See $mmaModWorkshopHelper#storeFiles.
|
||||
* Get a list of stored attachment files for an assessment and online files also. See AddonModWorkshopHelperProvider#storeFiles.
|
||||
*
|
||||
* @param {object} filesObject Files object combining offline and online information.
|
||||
* @param {number} workshopId Workshop ID.
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
// (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';
|
||||
import { AddonModWorkshopProvider } from './workshop';
|
||||
|
||||
/**
|
||||
* Handler to treat links to workshop.
|
||||
*/
|
||||
@Injectable()
|
||||
export class AddonModWorkshopLinkHandler extends CoreContentLinksModuleIndexHandler {
|
||||
name = 'AddonModWorkshopLinkHandler';
|
||||
|
||||
constructor(courseHelper: CoreCourseHelperProvider) {
|
||||
super(courseHelper, AddonModWorkshopProvider.COMPONENT, 'workshop');
|
||||
}
|
||||
}
|
|
@ -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 { AddonModWorkshopIndexComponent } from '../components/index/index';
|
||||
import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@core/course/providers/module-delegate';
|
||||
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||
import { AddonModWorkshopProvider } from './workshop';
|
||||
|
||||
/**
|
||||
* Handler to support workshop modules.
|
||||
*/
|
||||
@Injectable()
|
||||
export class AddonModWorkshopModuleHandler implements CoreCourseModuleHandler {
|
||||
name = 'AddonModWorkshop';
|
||||
modName = 'workshop';
|
||||
|
||||
constructor(private courseProvider: CoreCourseProvider, private workshopProvider: AddonModWorkshopProvider) { }
|
||||
|
||||
/**
|
||||
* Check if the handler is enabled on a site level.
|
||||
*
|
||||
* @return {Promise<boolean>} Whether or not the handler is enabled on a site level.
|
||||
*/
|
||||
isEnabled(): Promise<boolean> {
|
||||
return this.workshopProvider.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('workshop'),
|
||||
title: module.name,
|
||||
class: 'addon-mod_workshop-handler',
|
||||
showDownloadButton: true,
|
||||
action(event: Event, navCtrl: NavController, module: any, courseId: number, options: NavOptions): void {
|
||||
navCtrl.push('AddonModWorkshopIndexPage', {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 AddonModWorkshopIndexComponent;
|
||||
}
|
||||
}
|
|
@ -418,7 +418,7 @@ export class AddonModWorkshopOfflineProvider {
|
|||
getAllAssessments(siteId?: string): Promise<any[]> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
return site.getDb().getRecords(this.ASSESSMENTS_TABLE).then((records) => {
|
||||
records.forEach(this.parseAssessnentRecord.bind(this));
|
||||
records.forEach(this.parseAssessmentRecord.bind(this));
|
||||
|
||||
return records;
|
||||
});
|
||||
|
@ -439,7 +439,7 @@ export class AddonModWorkshopOfflineProvider {
|
|||
};
|
||||
|
||||
return site.getDb().getRecords(this.ASSESSMENTS_TABLE, conditions).then((records) => {
|
||||
records.forEach(this.parseAssessnentRecord.bind(this));
|
||||
records.forEach(this.parseAssessmentRecord.bind(this));
|
||||
|
||||
return records;
|
||||
});
|
||||
|
@ -462,7 +462,7 @@ export class AddonModWorkshopOfflineProvider {
|
|||
};
|
||||
|
||||
return site.getDb().getRecord(this.ASSESSMENTS_TABLE, conditions).then((record) => {
|
||||
this.parseAssessnentRecord(record);
|
||||
this.parseAssessmentRecord(record);
|
||||
|
||||
return record;
|
||||
});
|
||||
|
@ -498,7 +498,7 @@ export class AddonModWorkshopOfflineProvider {
|
|||
*
|
||||
* @param {any} record Assessnent record, modified in place.
|
||||
*/
|
||||
protected parseAssessnentRecord(record: any): void {
|
||||
protected parseAssessmentRecord(record: any): void {
|
||||
record.inputdata = this.textUtils.parseJSON(record.inputdata);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ import { AddonModWorkshopOfflineProvider } from './offline';
|
|||
*/
|
||||
@Injectable()
|
||||
export class AddonModWorkshopProvider {
|
||||
static COMPONENT = 'mmaWorkshopUrl';
|
||||
static COMPONENT = 'mmaModWorkshop';
|
||||
static PER_PAGE = 10;
|
||||
static PHASE_SETUP = 10;
|
||||
static PHASE_SUBMISSION = 20;
|
||||
|
@ -35,6 +35,9 @@ export class AddonModWorkshopProvider {
|
|||
static EXAMPLES_BEFORE_SUBMISSION: 1;
|
||||
static EXAMPLES_BEFORE_ASSESSMENT: 2;
|
||||
|
||||
static SUBMISSION_CHANGED = 'addon_mod_workshop_submission_changed';
|
||||
static ASSESSMENT_SAVED = 'addon_mod_workshop_assessment_saved';
|
||||
|
||||
protected ROOT_CACHE_KEY = 'mmaModWorkshop:';
|
||||
|
||||
constructor(
|
||||
|
@ -346,12 +349,7 @@ export class AddonModWorkshopProvider {
|
|||
|
||||
return site.read('mod_workshop_get_user_plan', params, preSets).then((response) => {
|
||||
if (response && response.userplan && response.userplan.phases) {
|
||||
const phases = {};
|
||||
response.userplan.phases.forEach((phase) => {
|
||||
phases[phase.code] = phase;
|
||||
});
|
||||
|
||||
return phases;
|
||||
return this.utils.arrayToObject(response.userplan.phases, 'code');
|
||||
}
|
||||
|
||||
return Promise.reject(null);
|
||||
|
@ -1295,7 +1293,7 @@ export class AddonModWorkshopProvider {
|
|||
|
||||
/**
|
||||
* Invalidate the prefetched content except files.
|
||||
* To invalidate files, use $mmaModWorkshop#invalidateFiles.
|
||||
* To invalidate files, use AddonModWorkshopProvider#invalidateFiles.
|
||||
*
|
||||
* @param {number} moduleId The module ID.
|
||||
* @param {number} courseId Course ID.
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
// (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 { CoreContentLinksDelegate } from '@core/contentlinks/providers/delegate';
|
||||
import { CoreCourseModuleDelegate } from '@core/course/providers/module-delegate';
|
||||
import { AddonModWorkshopComponentsModule } from './components/components.module';
|
||||
import { AddonModWorkshopModuleHandler } from './providers/module-handler';
|
||||
import { AddonModWorkshopProvider } from './providers/workshop';
|
||||
import { AddonModWorkshopLinkHandler } from './providers/link-handler';
|
||||
import { AddonModWorkshopOfflineProvider } from './providers/offline';
|
||||
import { AddonModWorkshopSyncProvider } from './providers/sync';
|
||||
import { AddonModWorkshopHelperProvider } from './providers/helper';
|
||||
import { AddonWorkshopAssessmentStrategyDelegate } from './providers/assessment-strategy-delegate';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
],
|
||||
imports: [
|
||||
AddonModWorkshopComponentsModule
|
||||
],
|
||||
providers: [
|
||||
AddonModWorkshopProvider,
|
||||
AddonModWorkshopModuleHandler,
|
||||
AddonModWorkshopLinkHandler,
|
||||
AddonModWorkshopOfflineProvider,
|
||||
AddonModWorkshopSyncProvider,
|
||||
AddonModWorkshopHelperProvider,
|
||||
AddonWorkshopAssessmentStrategyDelegate
|
||||
]
|
||||
})
|
||||
export class AddonModWorkshopModule {
|
||||
constructor(moduleDelegate: CoreCourseModuleDelegate, moduleHandler: AddonModWorkshopModuleHandler,
|
||||
contentLinksDelegate: CoreContentLinksDelegate, linkHandler: AddonModWorkshopLinkHandler) {
|
||||
moduleDelegate.registerHandler(moduleHandler);
|
||||
contentLinksDelegate.registerHandler(linkHandler);
|
||||
}
|
||||
}
|
|
@ -96,6 +96,7 @@ import { AddonModQuizModule } from '@addon/mod/quiz/quiz.module';
|
|||
import { AddonModScormModule } from '@addon/mod/scorm/scorm.module';
|
||||
import { AddonModUrlModule } from '@addon/mod/url/url.module';
|
||||
import { AddonModSurveyModule } from '@addon/mod/survey/survey.module';
|
||||
import { AddonModWorkshopModule } from '@addon/mod/workshop/workshop.module';
|
||||
import { AddonModImscpModule } from '@addon/mod/imscp/imscp.module';
|
||||
import { AddonModWikiModule } from '@addon/mod/wiki/wiki.module';
|
||||
import { AddonMessageOutputModule } from '@addon/messageoutput/messageoutput.module';
|
||||
|
@ -202,6 +203,7 @@ export const CORE_PROVIDERS: any[] = [
|
|||
AddonModScormModule,
|
||||
AddonModUrlModule,
|
||||
AddonModSurveyModule,
|
||||
AddonModWorkshopModule,
|
||||
AddonModImscpModule,
|
||||
AddonModWikiModule,
|
||||
AddonMessageOutputModule,
|
||||
|
|
Loading…
Reference in New Issue