Skip to content

Commit 7eec78f

Browse files
authored
Merge pull request #2281 from dpalou/MOBILE-3323
Mobile 3323
2 parents 00d0838 + 7d026fd commit 7eec78f

File tree

99 files changed

+1248
-307
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

99 files changed

+1248
-307
lines changed

scripts/langindex.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1482,6 +1482,8 @@
14821482
"core.downloaded": "local_moodlemobileapp",
14831483
"core.downloading": "local_moodlemobileapp",
14841484
"core.edit": "moodle",
1485+
"core.editor.autosavesucceeded": "editor_atto",
1486+
"core.editor.textrecovered": "editor_atto",
14851487
"core.emptysplit": "local_moodlemobileapp",
14861488
"core.error": "moodle",
14871489
"core.errorchangecompletion": "local_moodlemobileapp",

src/addon/calendar/pages/edit-event/edit-event.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
</ion-refresher>
1010

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

9292
<!-- Location. -->

src/addon/calendar/pages/edit-event/edit-event.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { IonicPageModule } from 'ionic-angular';
1717
import { TranslateModule } from '@ngx-translate/core';
1818
import { CoreComponentsModule } from '@components/components.module';
1919
import { CoreDirectivesModule } from '@directives/directives.module';
20+
import { CoreEditorComponentsModule } from '@core/editor/components/components.module';
2021
import { AddonCalendarEditEventPage } from './edit-event';
2122

2223
@NgModule({
@@ -26,6 +27,7 @@ import { AddonCalendarEditEventPage } from './edit-event';
2627
imports: [
2728
CoreComponentsModule,
2829
CoreDirectivesModule,
30+
CoreEditorComponentsModule,
2931
IonicPageModule.forChild(AddonCalendarEditEventPage),
3032
TranslateModule.forChild()
3133
],

src/addon/calendar/pages/edit-event/edit-event.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

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

46-
@ViewChild(CoreRichTextEditorComponent) descriptionEditor: CoreRichTextEditorComponent;
46+
@ViewChild(CoreEditorRichTextEditorComponent) descriptionEditor: CoreEditorRichTextEditorComponent;
47+
@ViewChild('editEventForm') formElement: ElementRef;
4748

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

500+
this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, result.sent, this.currentSite.getId());
501+
499502
if (result.sent) {
500503
// Event created or edited, invalidate right days & months.
501504
const numberOfRepetitions = formData.repeat ? formData.repeats :
@@ -557,6 +560,9 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy {
557560
discard(): void {
558561
this.domUtils.showConfirm(this.translate.instant('core.areyousure')).then(() => {
559562
this.calendarOffline.deleteEvent(this.eventId).then(() => {
563+
564+
this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.currentSite.getId());
565+
560566
this.returnToList();
561567
}).catch(() => {
562568
// Shouldn't happen.
@@ -572,16 +578,18 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy {
572578
*
573579
* @return Resolved if we can leave it, rejected if not.
574580
*/
575-
ionViewCanLeave(): boolean | Promise<void> {
576-
581+
async ionViewCanLeave(): Promise<void> {
577582
if (this.calendarHelper.hasEventDataChanged(this.eventForm.value, this.originalData)) {
578583
// Show confirmation if some data has been modified.
579-
return this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit'));
580-
} else {
581-
return Promise.resolve();
584+
await this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit'));
582585
}
586+
587+
this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.currentSite.getId());
583588
}
584589

590+
/**
591+
* Unblock sync.
592+
*/
585593
protected unblockSync(): void {
586594
if (this.eventId) {
587595
this.syncProvider.unblockOperation(AddonCalendarProvider.COMPONENT, this.eventId);

src/addon/mod/assign/feedback/comments/comments.module.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { AddonModAssignFeedbackCommentsComponent } from './component/comments';
2121
import { AddonModAssignFeedbackDelegate } from '../../providers/feedback-delegate';
2222
import { CoreComponentsModule } from '@components/components.module';
2323
import { CoreDirectivesModule } from '@directives/directives.module';
24+
import { CoreEditorComponentsModule } from '@core/editor/components/components.module';
2425

2526
@NgModule({
2627
declarations: [
@@ -31,7 +32,8 @@ import { CoreDirectivesModule } from '@directives/directives.module';
3132
IonicModule,
3233
TranslateModule.forChild(),
3334
CoreComponentsModule,
34-
CoreDirectivesModule
35+
CoreDirectivesModule,
36+
CoreEditorComponentsModule,
3537
],
3638
providers: [
3739
AddonModAssignFeedbackCommentsHandler

src/addon/mod/assign/feedback/comments/component/addon-mod-assign-feedback-comments.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,6 @@ <h2>{{ plugin.name }}</h2>
1919

2020
<!-- Edit -->
2121
<ion-item text-wrap *ngIf="edit && loaded">
22-
<core-rich-text-editor item-content [control]="control" [placeholder]="plugin.name" name="assignfeedbackcomments_editor" [component]="component" [componentId]="assign.cmid"></core-rich-text-editor>
22+
<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'}">
23+
</core-rich-text-editor>
2324
</ion-item>

src/addon/mod/assign/pages/edit-feedback-modal/edit-feedback-modal.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
</ion-navbar>
1010
</ion-header>
1111
<ion-content>
12-
<form name="addon-mod_assign-edit-feedback-form" *ngIf="userId && plugin">
12+
<form name="addon-mod_assign-edit-feedback-form" *ngIf="userId && plugin" #editFeedbackForm>
1313
<addon-mod-assign-feedback-plugin [assign]="assign" [submission]="submission" [userId]="userId" [plugin]="plugin" [edit]="true"></addon-mod-assign-feedback-plugin>
1414
<button ion-button block (click)="done($event)">{{ 'core.done' | translate }}</button>
1515
</form>

src/addon/mod/assign/pages/edit-feedback-modal/edit-feedback-modal.ts

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

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

41+
@ViewChild('editFeedbackForm') formElement: ElementRef;
42+
3943
protected forceLeave = false; // To allow leaving the page without checking for changes.
4044

41-
constructor(params: NavParams, protected viewCtrl: ViewController, protected domUtils: CoreDomUtilsProvider,
42-
protected translate: TranslateService, protected feedbackDelegate: AddonModAssignFeedbackDelegate) {
45+
constructor(params: NavParams,
46+
protected viewCtrl: ViewController,
47+
protected domUtils: CoreDomUtilsProvider,
48+
protected translate: TranslateService,
49+
protected feedbackDelegate: AddonModAssignFeedbackDelegate,
50+
protected eventsProvider: CoreEventsProvider,
51+
protected sitesProvider: CoreSitesProvider) {
4352

4453
this.assign = params.get('assign');
4554
this.submission = params.get('submission');
@@ -52,16 +61,17 @@ export class AddonModAssignEditFeedbackModalPage {
5261
*
5362
* @return Resolved if we can leave it, rejected if not.
5463
*/
55-
ionViewCanLeave(): boolean | Promise<void> {
64+
async ionViewCanLeave(): Promise<void> {
5665
if (this.forceLeave) {
57-
return true;
66+
return;
5867
}
5968

60-
return this.hasDataChanged().then((changed) => {
61-
if (changed) {
62-
return this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit'));
63-
}
64-
});
69+
const changed = await this.hasDataChanged();
70+
if (changed) {
71+
await this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit'));
72+
}
73+
74+
this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.sitesProvider.getCurrentSiteId());
6575
}
6676

6777
/**
@@ -82,6 +92,8 @@ export class AddonModAssignEditFeedbackModalPage {
8292
e.preventDefault();
8393
e.stopPropagation();
8494

95+
this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, false, this.sitesProvider.getCurrentSiteId());
96+
8597
// Close the modal, sending the input data.
8698
this.forceLeave = true;
8799
this.closeModal(this.getInputData());

src/addon/mod/assign/pages/edit/edit.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<core-loading [hideUntil]="loaded">
1414
<ion-list>
1515
<!-- @todo: plagiarism_print_disclosure -->
16-
<form name="addon-mod_assign-edit-form" *ngIf="userSubmission && userSubmission.plugins && userSubmission.plugins.length">
16+
<form name="addon-mod_assign-edit-form" *ngIf="userSubmission && userSubmission.plugins && userSubmission.plugins.length" #editSubmissionForm>
1717
<!-- Submission statement. -->
1818
<ion-item text-wrap *ngIf="submissionStatement">
1919
<ion-label><core-format-text [text]="submissionStatement" [filter]="false"></core-format-text></ion-label>

src/addon/mod/assign/pages/edit/edit.ts

Lines changed: 66 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
import { Component, OnInit, OnDestroy } from '@angular/core';
15+
import { Component, OnInit, OnDestroy, ViewChild, ElementRef } from '@angular/core';
1616
import { IonicPage, NavController, NavParams } from 'ionic-angular';
1717
import { TranslateService } from '@ngx-translate/core';
1818
import { CoreEventsProvider } from '@providers/events';
@@ -34,6 +34,9 @@ import { AddonModAssignHelperProvider } from '../../providers/helper';
3434
templateUrl: 'edit.html',
3535
})
3636
export class AddonModAssignEditPage implements OnInit, OnDestroy {
37+
38+
@ViewChild('editSubmissionForm') formElement: ElementRef;
39+
3740
title: string; // Title to display.
3841
assign: AddonModAssignAssign; // Assignment.
3942
courseId: number; // Course ID the assignment belongs to.
@@ -82,20 +85,21 @@ export class AddonModAssignEditPage implements OnInit, OnDestroy {
8285
*
8386
* @return Resolved if we can leave it, rejected if not.
8487
*/
85-
ionViewCanLeave(): boolean | Promise<void> {
88+
async ionViewCanLeave(): Promise<void> {
8689
if (this.forceLeave) {
87-
return true;
90+
return;
8891
}
8992

9093
// Check if data has changed.
91-
return this.hasDataChanged().then((changed) => {
92-
if (changed) {
93-
return this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit'));
94-
}
95-
}).then(() => {
96-
// Nothing has changed or user confirmed to leave. Clear temporary data from plugins.
97-
this.assignHelper.clearSubmissionPluginTmpData(this.assign, this.userSubmission, this.getInputData());
98-
});
94+
const changed = await this.hasDataChanged();
95+
if (changed) {
96+
await this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit'));
97+
}
98+
99+
// Nothing has changed or user confirmed to leave. Clear temporary data from plugins.
100+
this.assignHelper.clearSubmissionPluginTmpData(this.assign, this.userSubmission, this.getInputData());
101+
102+
this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.sitesProvider.getCurrentSiteId());
99103
}
100104

101105
/**
@@ -265,69 +269,74 @@ export class AddonModAssignEditPage implements OnInit, OnDestroy {
265269
*
266270
* @return Promise resolved when done.
267271
*/
268-
protected saveSubmission(): Promise<any> {
272+
protected async saveSubmission(): Promise<void> {
269273
const inputData = this.getInputData();
270274

271275
if (this.submissionStatement && (!inputData.submissionstatement || inputData.submissionstatement === 'false')) {
272-
return Promise.reject(this.translate.instant('addon.mod_assign.acceptsubmissionstatement'));
276+
throw this.translate.instant('addon.mod_assign.acceptsubmissionstatement');
273277
}
274278

275279
let modal = this.domUtils.showModalLoading();
280+
let size;
276281

277282
// Get size to ask for confirmation.
278-
return this.assignHelper.getSubmissionSizeForEdit(this.assign, this.userSubmission, inputData).catch(() => {
283+
try {
284+
size = await this.assignHelper.getSubmissionSizeForEdit(this.assign, this.userSubmission, inputData);
285+
} catch (error) {
279286
// Error calculating size, return -1.
280-
return -1;
281-
}).then((size) => {
282-
modal.dismiss();
287+
size = -1;
288+
}
289+
290+
modal.dismiss();
283291

292+
try {
284293
// Confirm action.
285-
return this.fileUploaderHelper.confirmUploadFile(size, true, this.allowOffline);
286-
}).then(() => {
294+
await this.fileUploaderHelper.confirmUploadFile(size, true, this.allowOffline);
295+
287296
modal = this.domUtils.showModalLoading('core.sending', true);
288297

289-
return this.prepareSubmissionData(inputData).then((pluginData) => {
290-
if (!Object.keys(pluginData).length) {
291-
// Nothing to save.
292-
return;
293-
}
298+
const pluginData = await this.prepareSubmissionData(inputData);
299+
if (!Object.keys(pluginData).length) {
300+
// Nothing to save.
301+
return;
302+
}
294303

295-
let promise;
304+
let sent: boolean;
296305

297-
if (this.saveOffline) {
298-
// Save submission in offline.
299-
promise = this.assignOfflineProvider.saveSubmission(this.assign.id, this.courseId, pluginData,
300-
this.userSubmission.timemodified, !this.assign.submissiondrafts, this.userId);
301-
} else {
302-
// Try to send it to server.
303-
promise = this.assignProvider.saveSubmission(this.assign.id, this.courseId, pluginData, this.allowOffline,
304-
this.userSubmission.timemodified, !!this.assign.submissiondrafts, this.userId);
305-
}
306+
if (this.saveOffline) {
307+
// Save submission in offline.
308+
sent = false;
309+
await this.assignOfflineProvider.saveSubmission(this.assign.id, this.courseId, pluginData,
310+
this.userSubmission.timemodified, !this.assign.submissiondrafts, this.userId);
311+
} else {
312+
// Try to send it to server.
313+
sent = await this.assignProvider.saveSubmission(this.assign.id, this.courseId, pluginData, this.allowOffline,
314+
this.userSubmission.timemodified, !!this.assign.submissiondrafts, this.userId);
315+
}
306316

307-
return promise.then(() => {
308-
// Clear temporary data from plugins.
309-
return this.assignHelper.clearSubmissionPluginTmpData(this.assign, this.userSubmission, inputData);
310-
}).then(() => {
311-
// Submission saved, trigger event.
312-
const params = {
313-
assignmentId: this.assign.id,
314-
submissionId: this.userSubmission.id,
315-
userId: this.userId,
316-
};
317-
318-
this.eventsProvider.trigger(AddonModAssignProvider.SUBMISSION_SAVED_EVENT, params,
319-
this.sitesProvider.getCurrentSiteId());
320-
321-
if (!this.assign.submissiondrafts) {
322-
// No drafts allowed, so it was submitted. Trigger event.
323-
this.eventsProvider.trigger(AddonModAssignProvider.SUBMITTED_FOR_GRADING_EVENT, params,
324-
this.sitesProvider.getCurrentSiteId());
325-
}
326-
});
327-
});
328-
}).finally(() => {
317+
// Clear temporary data from plugins.
318+
await this.assignHelper.clearSubmissionPluginTmpData(this.assign, this.userSubmission, inputData);
319+
320+
// Submission saved, trigger events.
321+
this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, sent, this.sitesProvider.getCurrentSiteId());
322+
323+
const params = {
324+
assignmentId: this.assign.id,
325+
submissionId: this.userSubmission.id,
326+
userId: this.userId,
327+
};
328+
329+
this.eventsProvider.trigger(AddonModAssignProvider.SUBMISSION_SAVED_EVENT, params,
330+
this.sitesProvider.getCurrentSiteId());
331+
332+
if (!this.assign.submissiondrafts) {
333+
// No drafts allowed, so it was submitted. Trigger event.
334+
this.eventsProvider.trigger(AddonModAssignProvider.SUBMITTED_FOR_GRADING_EVENT, params,
335+
this.sitesProvider.getCurrentSiteId());
336+
}
337+
} finally {
329338
modal.dismiss();
330-
});
339+
}
331340
}
332341

333342
/**

0 commit comments

Comments
 (0)