Skip to content
Merged
2 changes: 2 additions & 0 deletions scripts/langindex.json
Original file line number Diff line number Diff line change
Expand Up @@ -1482,6 +1482,8 @@
"core.downloaded": "local_moodlemobileapp",
"core.downloading": "local_moodlemobileapp",
"core.edit": "moodle",
"core.editor.autosavesucceeded": "editor_atto",
"core.editor.textrecovered": "editor_atto",
"core.emptysplit": "local_moodlemobileapp",
"core.error": "moodle",
"core.errorchangecompletion": "local_moodlemobileapp",
Expand Down
4 changes: 2 additions & 2 deletions src/addon/calendar/pages/edit-event/edit-event.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
</ion-refresher>

<core-loading [hideUntil]="loaded">
<form ion-list [formGroup]="eventForm" *ngIf="!error">
<form ion-list [formGroup]="eventForm" *ngIf="!error" #editEventForm>
<!-- Event name. -->
<ion-item text-wrap>
<ion-label stacked><h2 [core-mark-required]="true">{{ 'addon.calendar.eventname' | translate }}</h2></ion-label>
Expand Down Expand Up @@ -86,7 +86,7 @@
<!-- Description. -->
<ion-item text-wrap>
<ion-label stacked><h2>{{ 'core.description' | translate }}</h2></ion-label>
<core-rich-text-editor item-content [control]="descriptionControl" [placeholder]="'core.description' | translate" name="description" [component]="component" [componentId]="eventId"></core-rich-text-editor>
<core-rich-text-editor item-content [control]="descriptionControl" [placeholder]="'core.description' | translate" name="description" [component]="component" [componentId]="eventId" [autoSave]="false"></core-rich-text-editor>
</ion-item>

<!-- Location. -->
Expand Down
2 changes: 2 additions & 0 deletions src/addon/calendar/pages/edit-event/edit-event.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { IonicPageModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
import { CoreEditorComponentsModule } from '@core/editor/components/components.module';
import { AddonCalendarEditEventPage } from './edit-event';

@NgModule({
Expand All @@ -26,6 +27,7 @@ import { AddonCalendarEditEventPage } from './edit-event';
imports: [
CoreComponentsModule,
CoreDirectivesModule,
CoreEditorComponentsModule,
IonicPageModule.forChild(AddonCalendarEditEventPage),
TranslateModule.forChild()
],
Expand Down
24 changes: 16 additions & 8 deletions src/addon/calendar/pages/edit-event/edit-event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import { Component, OnInit, OnDestroy, Optional, ViewChild } from '@angular/core';
import { Component, OnInit, OnDestroy, Optional, ViewChild, ElementRef } from '@angular/core';
import { FormControl, FormGroup, FormBuilder, Validators } from '@angular/forms';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
import { TranslateService } from '@ngx-translate/core';
Expand All @@ -25,7 +25,7 @@ import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreCoursesProvider } from '@core/courses/providers/courses';
import { CoreSplitViewComponent } from '@components/split-view/split-view';
import { CoreRichTextEditorComponent } from '@components/rich-text-editor/rich-text-editor.ts';
import { CoreEditorRichTextEditorComponent } from '@core/editor/components/rich-text-editor/rich-text-editor.ts';
import { AddonCalendarProvider, AddonCalendarGetAccessInfoResult, AddonCalendarEvent } from '../../providers/calendar';
import { AddonCalendarOfflineProvider } from '../../providers/calendar-offline';
import { AddonCalendarHelperProvider } from '../../providers/helper';
Expand All @@ -43,7 +43,8 @@ import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
})
export class AddonCalendarEditEventPage implements OnInit, OnDestroy {

@ViewChild(CoreRichTextEditorComponent) descriptionEditor: CoreRichTextEditorComponent;
@ViewChild(CoreEditorRichTextEditorComponent) descriptionEditor: CoreEditorRichTextEditorComponent;
@ViewChild('editEventForm') formElement: ElementRef;

title: string;
dateFormat: string;
Expand Down Expand Up @@ -496,6 +497,8 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy {
this.calendarProvider.submitEvent(this.eventId, data).then((result) => {
event = result.event;

this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, result.sent, this.currentSite.getId());

if (result.sent) {
// Event created or edited, invalidate right days & months.
const numberOfRepetitions = formData.repeat ? formData.repeats :
Expand Down Expand Up @@ -557,6 +560,9 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy {
discard(): void {
this.domUtils.showConfirm(this.translate.instant('core.areyousure')).then(() => {
this.calendarOffline.deleteEvent(this.eventId).then(() => {

this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.currentSite.getId());

this.returnToList();
}).catch(() => {
// Shouldn't happen.
Expand All @@ -572,16 +578,18 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy {
*
* @return Resolved if we can leave it, rejected if not.
*/
ionViewCanLeave(): boolean | Promise<void> {

async ionViewCanLeave(): Promise<void> {
if (this.calendarHelper.hasEventDataChanged(this.eventForm.value, this.originalData)) {
// Show confirmation if some data has been modified.
return this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit'));
} else {
return Promise.resolve();
await this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit'));
}

this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.currentSite.getId());
}

/**
* Unblock sync.
*/
protected unblockSync(): void {
if (this.eventId) {
this.syncProvider.unblockOperation(AddonCalendarProvider.COMPONENT, this.eventId);
Expand Down
4 changes: 3 additions & 1 deletion src/addon/mod/assign/feedback/comments/comments.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { AddonModAssignFeedbackCommentsComponent } from './component/comments';
import { AddonModAssignFeedbackDelegate } from '../../providers/feedback-delegate';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
import { CoreEditorComponentsModule } from '@core/editor/components/components.module';

@NgModule({
declarations: [
Expand All @@ -31,7 +32,8 @@ import { CoreDirectivesModule } from '@directives/directives.module';
IonicModule,
TranslateModule.forChild(),
CoreComponentsModule,
CoreDirectivesModule
CoreDirectivesModule,
CoreEditorComponentsModule,
],
providers: [
AddonModAssignFeedbackCommentsHandler
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ <h2>{{ plugin.name }}</h2>

<!-- Edit -->
<ion-item text-wrap *ngIf="edit && loaded">
<core-rich-text-editor item-content [control]="control" [placeholder]="plugin.name" name="assignfeedbackcomments_editor" [component]="component" [componentId]="assign.cmid"></core-rich-text-editor>
<core-rich-text-editor item-content [control]="control" [placeholder]="plugin.name" name="assignfeedbackcomments_editor" [component]="component" [componentId]="assign.cmid" [autoSave]="true" contextLevel="module" [contextInstanceId]="assign.cmid" elementId="assignfeedbackcomments_editor" [draftExtraParams]="{userid: userId, action: 'grade'}">
</core-rich-text-editor>
</ion-item>
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
</ion-navbar>
</ion-header>
<ion-content>
<form name="addon-mod_assign-edit-feedback-form" *ngIf="userId && plugin">
<form name="addon-mod_assign-edit-feedback-form" *ngIf="userId && plugin" #editFeedbackForm>
<addon-mod-assign-feedback-plugin [assign]="assign" [submission]="submission" [userId]="userId" [plugin]="plugin" [edit]="true"></addon-mod-assign-feedback-plugin>
<button ion-button block (click)="done($event)">{{ 'core.done' | translate }}</button>
</form>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import { Component, Input } from '@angular/core';
import { Component, Input, ViewChild, ElementRef } from '@angular/core';
import { IonicPage, ViewController, NavParams } from 'ionic-angular';
import { TranslateService } from '@ngx-translate/core';
import { CoreEventsProvider } from '@providers/events';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { AddonModAssignFeedbackDelegate } from '../../providers/feedback-delegate';
import {
Expand All @@ -36,10 +38,17 @@ export class AddonModAssignEditFeedbackModalPage {
@Input() plugin: AddonModAssignPlugin; // The plugin object.
@Input() userId: number; // The user ID of the submission.

@ViewChild('editFeedbackForm') formElement: ElementRef;

protected forceLeave = false; // To allow leaving the page without checking for changes.

constructor(params: NavParams, protected viewCtrl: ViewController, protected domUtils: CoreDomUtilsProvider,
protected translate: TranslateService, protected feedbackDelegate: AddonModAssignFeedbackDelegate) {
constructor(params: NavParams,
protected viewCtrl: ViewController,
protected domUtils: CoreDomUtilsProvider,
protected translate: TranslateService,
protected feedbackDelegate: AddonModAssignFeedbackDelegate,
protected eventsProvider: CoreEventsProvider,
protected sitesProvider: CoreSitesProvider) {

this.assign = params.get('assign');
this.submission = params.get('submission');
Expand All @@ -52,16 +61,17 @@ export class AddonModAssignEditFeedbackModalPage {
*
* @return Resolved if we can leave it, rejected if not.
*/
ionViewCanLeave(): boolean | Promise<void> {
async ionViewCanLeave(): Promise<void> {
if (this.forceLeave) {
return true;
return;
}

return this.hasDataChanged().then((changed) => {
if (changed) {
return this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit'));
}
});
const changed = await this.hasDataChanged();
if (changed) {
await this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit'));
}

this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.sitesProvider.getCurrentSiteId());
}

/**
Expand All @@ -82,6 +92,8 @@ export class AddonModAssignEditFeedbackModalPage {
e.preventDefault();
e.stopPropagation();

this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, false, this.sitesProvider.getCurrentSiteId());

// Close the modal, sending the input data.
this.forceLeave = true;
this.closeModal(this.getInputData());
Expand Down
2 changes: 1 addition & 1 deletion src/addon/mod/assign/pages/edit/edit.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<core-loading [hideUntil]="loaded">
<ion-list>
<!-- @todo: plagiarism_print_disclosure -->
<form name="addon-mod_assign-edit-form" *ngIf="userSubmission && userSubmission.plugins && userSubmission.plugins.length">
<form name="addon-mod_assign-edit-form" *ngIf="userSubmission && userSubmission.plugins && userSubmission.plugins.length" #editSubmissionForm>
<!-- Submission statement. -->
<ion-item text-wrap *ngIf="submissionStatement">
<ion-label><core-format-text [text]="submissionStatement" [filter]="false"></core-format-text></ion-label>
Expand Down
123 changes: 66 additions & 57 deletions src/addon/mod/assign/pages/edit/edit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Component, OnInit, OnDestroy, ViewChild, ElementRef } from '@angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
import { TranslateService } from '@ngx-translate/core';
import { CoreEventsProvider } from '@providers/events';
Expand All @@ -34,6 +34,9 @@ import { AddonModAssignHelperProvider } from '../../providers/helper';
templateUrl: 'edit.html',
})
export class AddonModAssignEditPage implements OnInit, OnDestroy {

@ViewChild('editSubmissionForm') formElement: ElementRef;

title: string; // Title to display.
assign: AddonModAssignAssign; // Assignment.
courseId: number; // Course ID the assignment belongs to.
Expand Down Expand Up @@ -82,20 +85,21 @@ export class AddonModAssignEditPage implements OnInit, OnDestroy {
*
* @return Resolved if we can leave it, rejected if not.
*/
ionViewCanLeave(): boolean | Promise<void> {
async ionViewCanLeave(): Promise<void> {
if (this.forceLeave) {
return true;
return;
}

// Check if data has changed.
return this.hasDataChanged().then((changed) => {
if (changed) {
return this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit'));
}
}).then(() => {
// Nothing has changed or user confirmed to leave. Clear temporary data from plugins.
this.assignHelper.clearSubmissionPluginTmpData(this.assign, this.userSubmission, this.getInputData());
});
const changed = await this.hasDataChanged();
if (changed) {
await this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit'));
}

// Nothing has changed or user confirmed to leave. Clear temporary data from plugins.
this.assignHelper.clearSubmissionPluginTmpData(this.assign, this.userSubmission, this.getInputData());

this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.sitesProvider.getCurrentSiteId());
}

/**
Expand Down Expand Up @@ -265,69 +269,74 @@ export class AddonModAssignEditPage implements OnInit, OnDestroy {
*
* @return Promise resolved when done.
*/
protected saveSubmission(): Promise<any> {
protected async saveSubmission(): Promise<void> {
const inputData = this.getInputData();

if (this.submissionStatement && (!inputData.submissionstatement || inputData.submissionstatement === 'false')) {
return Promise.reject(this.translate.instant('addon.mod_assign.acceptsubmissionstatement'));
throw this.translate.instant('addon.mod_assign.acceptsubmissionstatement');
}

let modal = this.domUtils.showModalLoading();
let size;

// Get size to ask for confirmation.
return this.assignHelper.getSubmissionSizeForEdit(this.assign, this.userSubmission, inputData).catch(() => {
try {
size = await this.assignHelper.getSubmissionSizeForEdit(this.assign, this.userSubmission, inputData);
} catch (error) {
// Error calculating size, return -1.
return -1;
}).then((size) => {
modal.dismiss();
size = -1;
}

modal.dismiss();

try {
// Confirm action.
return this.fileUploaderHelper.confirmUploadFile(size, true, this.allowOffline);
}).then(() => {
await this.fileUploaderHelper.confirmUploadFile(size, true, this.allowOffline);

modal = this.domUtils.showModalLoading('core.sending', true);

return this.prepareSubmissionData(inputData).then((pluginData) => {
if (!Object.keys(pluginData).length) {
// Nothing to save.
return;
}
const pluginData = await this.prepareSubmissionData(inputData);
if (!Object.keys(pluginData).length) {
// Nothing to save.
return;
}

let promise;
let sent: boolean;

if (this.saveOffline) {
// Save submission in offline.
promise = this.assignOfflineProvider.saveSubmission(this.assign.id, this.courseId, pluginData,
this.userSubmission.timemodified, !this.assign.submissiondrafts, this.userId);
} else {
// Try to send it to server.
promise = this.assignProvider.saveSubmission(this.assign.id, this.courseId, pluginData, this.allowOffline,
this.userSubmission.timemodified, !!this.assign.submissiondrafts, this.userId);
}
if (this.saveOffline) {
// Save submission in offline.
sent = false;
await this.assignOfflineProvider.saveSubmission(this.assign.id, this.courseId, pluginData,
this.userSubmission.timemodified, !this.assign.submissiondrafts, this.userId);
} else {
// Try to send it to server.
sent = await this.assignProvider.saveSubmission(this.assign.id, this.courseId, pluginData, this.allowOffline,
this.userSubmission.timemodified, !!this.assign.submissiondrafts, this.userId);
}

return promise.then(() => {
// Clear temporary data from plugins.
return this.assignHelper.clearSubmissionPluginTmpData(this.assign, this.userSubmission, inputData);
}).then(() => {
// Submission saved, trigger event.
const params = {
assignmentId: this.assign.id,
submissionId: this.userSubmission.id,
userId: this.userId,
};

this.eventsProvider.trigger(AddonModAssignProvider.SUBMISSION_SAVED_EVENT, params,
this.sitesProvider.getCurrentSiteId());

if (!this.assign.submissiondrafts) {
// No drafts allowed, so it was submitted. Trigger event.
this.eventsProvider.trigger(AddonModAssignProvider.SUBMITTED_FOR_GRADING_EVENT, params,
this.sitesProvider.getCurrentSiteId());
}
});
});
}).finally(() => {
// Clear temporary data from plugins.
await this.assignHelper.clearSubmissionPluginTmpData(this.assign, this.userSubmission, inputData);

// Submission saved, trigger events.
this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, sent, this.sitesProvider.getCurrentSiteId());

const params = {
assignmentId: this.assign.id,
submissionId: this.userSubmission.id,
userId: this.userId,
};

this.eventsProvider.trigger(AddonModAssignProvider.SUBMISSION_SAVED_EVENT, params,
this.sitesProvider.getCurrentSiteId());

if (!this.assign.submissiondrafts) {
// No drafts allowed, so it was submitted. Trigger event.
this.eventsProvider.trigger(AddonModAssignProvider.SUBMITTED_FOR_GRADING_EVENT, params,
this.sitesProvider.getCurrentSiteId());
}
} finally {
modal.dismiss();
});
}
}

/**
Expand Down
Loading