MOBILE-3323 editor: Discard draft when user cancels

main
Dani Palou 2020-02-07 13:19:58 +01:00
parent 90f96b762b
commit 3ab2e7ddc0
29 changed files with 191 additions and 216 deletions

View File

@ -497,10 +497,7 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy {
this.calendarProvider.submitEvent(this.eventId, data).then((result) => { this.calendarProvider.submitEvent(this.eventId, data).then((result) => {
event = result.event; event = result.event;
this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, { this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, result.sent, this.currentSite.getId());
form: this.formElement.nativeElement,
online: result.sent,
}, this.currentSite.getId());
if (result.sent) { if (result.sent) {
// Event created or edited, invalidate right days & months. // Event created or edited, invalidate right days & months.
@ -563,6 +560,9 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy {
discard(): void { discard(): void {
this.domUtils.showConfirm(this.translate.instant('core.areyousure')).then(() => { this.domUtils.showConfirm(this.translate.instant('core.areyousure')).then(() => {
this.calendarOffline.deleteEvent(this.eventId).then(() => { this.calendarOffline.deleteEvent(this.eventId).then(() => {
this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.currentSite.getId());
this.returnToList(); this.returnToList();
}).catch(() => { }).catch(() => {
// Shouldn't happen. // Shouldn't happen.
@ -578,16 +578,18 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy {
* *
* @return Resolved if we can leave it, rejected if not. * @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)) { if (this.calendarHelper.hasEventDataChanged(this.eventForm.value, this.originalData)) {
// Show confirmation if some data has been modified. // Show confirmation if some data has been modified.
return this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit')); await this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit'));
} else {
return Promise.resolve();
}
} }
this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.currentSite.getId());
}
/**
* Unblock sync.
*/
protected unblockSync(): void { protected unblockSync(): void {
if (this.eventId) { if (this.eventId) {
this.syncProvider.unblockOperation(AddonCalendarProvider.COMPONENT, this.eventId); this.syncProvider.unblockOperation(AddonCalendarProvider.COMPONENT, this.eventId);

View File

@ -61,16 +61,17 @@ export class AddonModAssignEditFeedbackModalPage {
* *
* @return Resolved if we can leave it, rejected if not. * @return Resolved if we can leave it, rejected if not.
*/ */
ionViewCanLeave(): boolean | Promise<void> { async ionViewCanLeave(): Promise<void> {
if (this.forceLeave) { if (this.forceLeave) {
return true; return;
} }
return this.hasDataChanged().then((changed) => { const changed = await this.hasDataChanged();
if (changed) { if (changed) {
return this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit')); await this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit'));
} }
});
this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.sitesProvider.getCurrentSiteId());
} }
/** /**
@ -91,10 +92,7 @@ export class AddonModAssignEditFeedbackModalPage {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, { this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, false, this.sitesProvider.getCurrentSiteId());
form: this.formElement.nativeElement,
online: false,
}, this.sitesProvider.getCurrentSiteId());
// Close the modal, sending the input data. // Close the modal, sending the input data.
this.forceLeave = true; this.forceLeave = true;

View File

@ -85,20 +85,21 @@ export class AddonModAssignEditPage implements OnInit, OnDestroy {
* *
* @return Resolved if we can leave it, rejected if not. * @return Resolved if we can leave it, rejected if not.
*/ */
ionViewCanLeave(): boolean | Promise<void> { async ionViewCanLeave(): Promise<void> {
if (this.forceLeave) { if (this.forceLeave) {
return true; return;
} }
// Check if data has changed. // Check if data has changed.
return this.hasDataChanged().then((changed) => { const changed = await this.hasDataChanged();
if (changed) { if (changed) {
return this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit')); await this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit'));
} }
}).then(() => {
// Nothing has changed or user confirmed to leave. Clear temporary data from plugins. // Nothing has changed or user confirmed to leave. Clear temporary data from plugins.
this.assignHelper.clearSubmissionPluginTmpData(this.assign, this.userSubmission, this.getInputData()); this.assignHelper.clearSubmissionPluginTmpData(this.assign, this.userSubmission, this.getInputData());
});
this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.sitesProvider.getCurrentSiteId());
} }
/** /**
@ -317,10 +318,7 @@ export class AddonModAssignEditPage implements OnInit, OnDestroy {
await this.assignHelper.clearSubmissionPluginTmpData(this.assign, this.userSubmission, inputData); await this.assignHelper.clearSubmissionPluginTmpData(this.assign, this.userSubmission, inputData);
// Submission saved, trigger events. // Submission saved, trigger events.
this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, { this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, sent, this.sitesProvider.getCurrentSiteId());
form: this.formElement.nativeElement,
online: sent,
}, this.sitesProvider.getCurrentSiteId());
const params = { const params = {
assignmentId: this.assign.id, assignmentId: this.assign.id,

View File

@ -96,28 +96,25 @@ export class AddonModDataEditPage {
* *
* @return Resolved if we can leave it, rejected if not. * @return Resolved if we can leave it, rejected if not.
*/ */
ionViewCanLeave(): boolean | Promise<void> { async ionViewCanLeave(): Promise<void> {
if (this.forceLeave || !this.entry) { if (this.forceLeave || !this.entry) {
return true; return;
} }
const inputData = this.editForm.value; const inputData = this.editForm.value;
return this.dataHelper.hasEditDataChanged(inputData, this.fieldsArray, this.data.id, const changed = await this.dataHelper.hasEditDataChanged(inputData, this.fieldsArray, this.data.id, this.entry.contents);
this.entry.contents).then((changed) => {
if (!changed) { if (changed) {
return Promise.resolve(); // Show confirmation if some data has been modified.
await this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit'));
} }
// Show confirmation if some data has been modified.
return this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit'));
}).then(() => {
// Delete the local files from the tmp folder. // Delete the local files from the tmp folder.
return this.dataHelper.getEditTmpFiles(inputData, this.fieldsArray, this.data.id, const files = await this.dataHelper.getEditTmpFiles(inputData, this.fieldsArray, this.data.id, this.entry.contents);
this.entry.contents).then((files) => {
this.fileUploaderProvider.clearTmpFiles(files); this.fileUploaderProvider.clearTmpFiles(files);
});
}); this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.siteId);
} }
/** /**
@ -218,10 +215,7 @@ export class AddonModDataEditPage {
// This is done if entry is updated when editing or creating if not. // This is done if entry is updated when editing or creating if not.
if ((this.entryId && result.updated) || (!this.entryId && result.newentryid)) { if ((this.entryId && result.updated) || (!this.entryId && result.newentryid)) {
this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, { this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, result.sent, this.siteId);
form: this.formElement.nativeElement,
online: result.sent,
}, this.siteId);
const promises = []; const promises = [];

View File

@ -186,6 +186,12 @@ export class AddonModDataSearchPage {
* @param data Data to return to the page. * @param data Data to return to the page.
*/ */
closeModal(data?: any): void { closeModal(data?: any): void {
if (typeof data == 'undefined') {
this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.sitesProvider.getCurrentSiteId());
} else {
this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, false, this.sitesProvider.getCurrentSiteId());
}
this.viewCtrl.dismiss(data); this.viewCtrl.dismiss(data);
} }
@ -220,11 +226,6 @@ export class AddonModDataSearchPage {
this.search.sortBy = searchedData.sortBy; this.search.sortBy = searchedData.sortBy;
this.search.sortDirection = searchedData.sortDirection; this.search.sortDirection = searchedData.sortDirection;
this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
form: this.formElement.nativeElement,
online: false,
}, this.sitesProvider.getCurrentSiteId());
this.closeModal(this.search); this.closeModal(this.search);
} }
} }

View File

@ -14,7 +14,6 @@
import { Component, Optional, Injector, Input, ViewChild, ElementRef } from '@angular/core'; import { Component, Optional, Injector, Input, ViewChild, ElementRef } from '@angular/core';
import { Content, NavController } from 'ionic-angular'; import { Content, NavController } from 'ionic-angular';
import { CoreEventsProvider } from '@providers/events';
import { CoreGroupsProvider, CoreGroupInfo } from '@providers/groups'; import { CoreGroupsProvider, CoreGroupInfo } from '@providers/groups';
import { CoreTimeUtilsProvider } from '@providers/utils/time'; import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreUtilsProvider } from '@providers/utils/utils';
@ -587,10 +586,7 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo
this.refreshIcon = 'refresh'; this.refreshIcon = 'refresh';
this.syncIcon = 'sync'; this.syncIcon = 'sync';
this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, { this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, true, this.siteId);
form: this.formElement.nativeElement,
online: true,
}, this.siteId);
}); });
} }

View File

@ -16,6 +16,7 @@ import { Component, ViewChild, ElementRef } from '@angular/core';
import { IonicPage, ViewController } from 'ionic-angular'; import { IonicPage, ViewController } from 'ionic-angular';
import { CoreEventsProvider } from '@providers/events'; import { CoreEventsProvider } from '@providers/events';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
/** /**
* Modal that asks the password for a lesson. * Modal that asks the password for a lesson.
@ -30,7 +31,8 @@ export class AddonModLessonPasswordModalPage {
constructor(protected viewCtrl: ViewController, constructor(protected viewCtrl: ViewController,
protected eventsProvider: CoreEventsProvider, protected eventsProvider: CoreEventsProvider,
protected sitesProvider: CoreSitesProvider) { } protected sitesProvider: CoreSitesProvider,
protected domUtils: CoreDomUtilsProvider) { }
/** /**
* Send the password back. * Send the password back.
@ -42,10 +44,7 @@ export class AddonModLessonPasswordModalPage {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, { this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, false, this.sitesProvider.getCurrentSiteId());
form: this.formElement.nativeElement,
online: false,
}, this.sitesProvider.getCurrentSiteId());
this.viewCtrl.dismiss(password.value); this.viewCtrl.dismiss(password.value);
} }
@ -54,6 +53,8 @@ export class AddonModLessonPasswordModalPage {
* Close modal. * Close modal.
*/ */
closeModal(): void { closeModal(): void {
this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.sitesProvider.getCurrentSiteId());
this.viewCtrl.dismiss(); this.viewCtrl.dismiss();
} }
} }

View File

@ -137,19 +137,19 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy {
* *
* @return Resolved if we can leave it, rejected if not. * @return Resolved if we can leave it, rejected if not.
*/ */
ionViewCanLeave(): boolean | Promise<void> { async ionViewCanLeave(): Promise<void> {
if (this.forceLeave) { if (this.forceLeave) {
return true; return;
} }
if (this.question && !this.eolData && !this.processData && this.originalData) { if (this.question && !this.eolData && !this.processData && this.originalData) {
// Question shown. Check if there is any change. // Question shown. Check if there is any change.
if (!this.utils.basicLeftCompare(this.questionForm.getRawValue(), this.originalData, 3)) { if (!this.utils.basicLeftCompare(this.questionForm.getRawValue(), this.originalData, 3)) {
return this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit')); await this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit'));
} }
} }
return Promise.resolve(); this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.sitesProvider.getCurrentSiteId());
} }
/** /**
@ -552,10 +552,8 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy {
return this.callFunction(this.lessonProvider.processPage.bind(this.lessonProvider), args, 6, 8).then((result) => { return this.callFunction(this.lessonProvider.processPage.bind(this.lessonProvider), args, 6, 8).then((result) => {
if (formSubmitted) { if (formSubmitted) {
this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, { this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, result.sent,
form: this.formElement.nativeElement, this.sitesProvider.getCurrentSiteId());
online: result.sent,
}, this.sitesProvider.getCurrentSiteId());
} }
if (!this.offline && !this.review && this.lessonProvider.isLessonOffline(this.lesson)) { if (!this.offline && !this.review && this.lessonProvider.isLessonOffline(this.lesson)) {

View File

@ -137,26 +137,28 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy {
* *
* @return Resolved if we can leave it, rejected if not. * @return Resolved if we can leave it, rejected if not.
*/ */
ionViewCanLeave(): boolean | Promise<void> { async ionViewCanLeave(): Promise<void> {
if (this.forceLeave) { if (this.forceLeave) {
return true; return;
} }
if (this.questions && this.questions.length && !this.showSummary) { if (this.questions && this.questions.length && !this.showSummary) {
// Save answers. // Save answers.
const modal = this.domUtils.showModalLoading('core.sending', true); const modal = this.domUtils.showModalLoading('core.sending', true);
return this.processAttempt(false, false).catch(() => { try {
await this.processAttempt(false, false);
} catch (error) {
// Save attempt failed. Show confirmation. // Save attempt failed. Show confirmation.
modal.dismiss(); modal.dismiss();
return this.domUtils.showConfirm(this.translate.instant('addon.mod_quiz.confirmleavequizonerror')); await this.domUtils.showConfirm(this.translate.instant('addon.mod_quiz.confirmleavequizonerror'));
}).finally(() => {
modal.dismiss();
});
}
return Promise.resolve(); this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.sitesProvider.getCurrentSiteId());
} finally {
modal.dismiss();
}
}
} }
/** /**
@ -587,10 +589,8 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy {
this.autoSave.cancelAutoSave(); this.autoSave.cancelAutoSave();
this.autoSave.hideAutoSaveError(); this.autoSave.hideAutoSaveError();
this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, { this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, !this.offline,
form: this.formElement.nativeElement, this.sitesProvider.getCurrentSiteId());
online: !this.offline,
}, this.sitesProvider.getCurrentSiteId());
}); });
} }

View File

@ -120,10 +120,7 @@ export class AddonModQuizPreflightModalPage implements OnInit {
this.domUtils.showErrorModal('core.errorinvalidform', true); this.domUtils.showErrorModal('core.errorinvalidform', true);
} }
} else { } else {
this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, { this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, false, this.siteId);
form: this.formElement.nativeElement,
online: false,
}, this.siteId);
this.viewCtrl.dismiss(this.preflightForm.value); this.viewCtrl.dismiss(this.preflightForm.value);
} }
@ -133,6 +130,8 @@ export class AddonModQuizPreflightModalPage implements OnInit {
* Close modal. * Close modal.
*/ */
closeModal(): void { closeModal(): void {
this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.siteId);
this.viewCtrl.dismiss(); this.viewCtrl.dismiss();
} }
} }

View File

@ -346,17 +346,17 @@ export class AddonModWikiEditPage implements OnInit, OnDestroy {
* *
* @return Resolved if we can leave it, rejected if not. * @return Resolved if we can leave it, rejected if not.
*/ */
ionViewCanLeave(): boolean | Promise<void> { async ionViewCanLeave(): Promise<void> {
if (this.forceLeave) { if (this.forceLeave) {
return true; return;
} }
// Check if data has changed. // Check if data has changed.
if (this.hasDataChanged()) { if (this.hasDataChanged()) {
return this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit')); await this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit'));
} }
return true; this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.sitesProvider.getCurrentSiteId());
} }
/** /**
@ -426,10 +426,8 @@ export class AddonModWikiEditPage implements OnInit, OnDestroy {
// Edit existing page. // Edit existing page.
promise = this.wikiProvider.editPage(this.pageId, text, this.section).then(() => { promise = this.wikiProvider.editPage(this.pageId, text, this.section).then(() => {
this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, { this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, true,
form: this.formElement.nativeElement, this.sitesProvider.getCurrentSiteId());
online: true,
}, this.sitesProvider.getCurrentSiteId());
// Invalidate page since it changed. // Invalidate page since it changed.
return this.wikiProvider.invalidatePage(this.pageId).then(() => { return this.wikiProvider.invalidatePage(this.pageId).then(() => {
@ -465,10 +463,8 @@ export class AddonModWikiEditPage implements OnInit, OnDestroy {
return this.wikiProvider.newPage(title, text, this.subwikiId, wikiId, this.userId, this.groupId).then((id) => { return this.wikiProvider.newPage(title, text, this.subwikiId, wikiId, this.userId, this.groupId).then((id) => {
this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, { this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, id > 0,
form: this.formElement.nativeElement, this.sitesProvider.getCurrentSiteId());
online: id > 0,
}, this.sitesProvider.getCurrentSiteId());
if (id > 0) { if (id > 0) {
// Page was created, get its data and go to the page. // Page was created, get its data and go to the page.

View File

@ -304,10 +304,7 @@ export class AddonModWorkshopAssessmentStrategyComponent implements OnInit {
assessmentData, false, allowOffline); assessmentData, false, allowOffline);
}).then((grade) => { }).then((grade) => {
this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, { this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, !!grade, this.sitesProvider.getCurrentSiteId());
form: this.formElement.nativeElement,
online: !!grade,
}, this.sitesProvider.getCurrentSiteId());
const promises = []; const promises = [];

View File

@ -120,17 +120,19 @@ export class AddonModWorkshopAssessmentPage implements OnInit, OnDestroy {
* *
* @return Resolved if we can leave it, rejected if not. * @return Resolved if we can leave it, rejected if not.
*/ */
ionViewCanLeave(): boolean | Promise<void> { async ionViewCanLeave(): Promise<void> {
if (this.forceLeave || !this.evaluating) { if (this.forceLeave || !this.evaluating) {
return true; return;
} }
if (!this.hasEvaluationChanged()) { if (!this.hasEvaluationChanged()) {
return Promise.resolve(); return;
} }
// Show confirmation if some data has been modified. // Show confirmation if some data has been modified.
return this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit')); await this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit'));
this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.siteId);
} }
/** /**
@ -344,10 +346,7 @@ export class AddonModWorkshopAssessmentPage implements OnInit, OnDestroy {
return this.workshopProvider.evaluateAssessment(this.workshopId, this.assessmentId, this.courseId, inputData.text, return this.workshopProvider.evaluateAssessment(this.workshopId, this.assessmentId, this.courseId, inputData.text,
inputData.weight, inputData.grade).then((result) => { inputData.weight, inputData.grade).then((result) => {
this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, { this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, !!result, this.siteId);
form: this.formElement.nativeElement,
online: !!result,
}, this.siteId);
const data = { const data = {
workshopId: this.workshopId, workshopId: this.workshopId,

View File

@ -112,27 +112,23 @@ export class AddonModWorkshopEditSubmissionPage implements OnInit, OnDestroy {
* *
* @return Resolved if we can leave it, rejected if not. * @return Resolved if we can leave it, rejected if not.
*/ */
ionViewCanLeave(): boolean | Promise<void> { async ionViewCanLeave(): Promise<void> {
if (this.forceLeave) { if (this.forceLeave) {
return true; return;
} }
let promise;
// Check if data has changed. // Check if data has changed.
if (!this.hasDataChanged()) { if (this.hasDataChanged()) {
promise = Promise.resolve();
} else {
// Show confirmation if some data has been modified. // Show confirmation if some data has been modified.
promise = this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit')); await this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit'));
} }
return promise.then(() => {
if (this.submission.attachmentfiles) { if (this.submission.attachmentfiles) {
// Delete the local files from the tmp folder. // Delete the local files from the tmp folder.
this.fileUploaderProvider.clearTmpFiles(this.submission.attachmentfiles); this.fileUploaderProvider.clearTmpFiles(this.submission.attachmentfiles);
} }
});
this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.siteId);
} }
/** /**
@ -378,10 +374,7 @@ export class AddonModWorkshopEditSubmissionPage implements OnInit, OnDestroy {
attachmentsId, undefined, submissionId, allowOffline); attachmentsId, undefined, submissionId, allowOffline);
}).then((newSubmissionId) => { }).then((newSubmissionId) => {
this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, { this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, !!newSubmissionId, this.siteId);
form: this.formElement.nativeElement,
online: !!newSubmissionId,
}, this.siteId);
const data = { const data = {
workshopId: this.workshopId, workshopId: this.workshopId,

View File

@ -144,14 +144,16 @@ export class AddonModWorkshopSubmissionPage implements OnInit, OnDestroy {
* *
* @return Resolved if we can leave it, rejected if not. * @return Resolved if we can leave it, rejected if not.
*/ */
ionViewCanLeave(): boolean | Promise<void> { async ionViewCanLeave(): Promise<void> {
const assessmentHasChanged = this.assessmentStrategy && this.assessmentStrategy.hasDataChanged(); const assessmentHasChanged = this.assessmentStrategy && this.assessmentStrategy.hasDataChanged();
if (this.forceLeave || (!this.hasEvaluationChanged() && !assessmentHasChanged)) { if (this.forceLeave || (!this.hasEvaluationChanged() && !assessmentHasChanged)) {
return true; return;
} }
// Show confirmation if some data has been modified. // Show confirmation if some data has been modified.
return this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit')); await this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit'));
this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.siteId);
} }
/** /**
@ -447,10 +449,7 @@ export class AddonModWorkshopSubmissionPage implements OnInit, OnDestroy {
return this.workshopProvider.evaluateSubmission(this.workshopId, this.submissionId, this.courseId, inputData.text, return this.workshopProvider.evaluateSubmission(this.workshopId, this.submissionId, this.courseId, inputData.text,
inputData.published, inputData.grade).then((result) => { inputData.published, inputData.grade).then((result) => {
this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, { this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, !!result, this.siteId);
form: this.formElement.nativeElement,
online: !!result,
}, this.siteId);
const data = { const data = {
workshopId: this.workshopId, workshopId: this.workshopId,

View File

@ -65,10 +65,7 @@ export class AddonNotesAddPage {
this.processing = true; this.processing = true;
this.notesProvider.addNote(this.userId, this.courseId, this.type, this.text).then((sent) => { this.notesProvider.addNote(this.userId, this.courseId, this.type, this.text).then((sent) => {
this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, { this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, sent, this.sitesProvider.getCurrentSiteId());
form: this.formElement.nativeElement,
online: sent,
}, this.sitesProvider.getCurrentSiteId());
this.viewCtrl.dismiss({type: this.type, sent: true}).finally(() => { this.viewCtrl.dismiss({type: this.type, sent: true}).finally(() => {
this.domUtils.showToast(sent ? 'addon.notes.eventnotecreated' : 'core.datastoredoffline', true, 3000); this.domUtils.showToast(sent ? 'addon.notes.eventnotecreated' : 'core.datastoredoffline', true, 3000);
@ -85,6 +82,8 @@ export class AddonNotesAddPage {
* Close modal. * Close modal.
*/ */
closeModal(): void { closeModal(): void {
this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.sitesProvider.getCurrentSiteId());
this.viewCtrl.dismiss({type: this.type}); this.viewCtrl.dismiss({type: this.type});
} }
} }

View File

@ -143,6 +143,7 @@ export class CoreLocalFileComponent implements OnInit {
if (newName == this.file.name) { if (newName == this.file.name) {
// Name hasn't changed, stop. // Name hasn't changed, stop.
this.editMode = false; this.editMode = false;
this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.sitesProvider.getCurrentSiteId());
return; return;
} }
@ -159,10 +160,8 @@ export class CoreLocalFileComponent implements OnInit {
// File doesn't exist, move it. // File doesn't exist, move it.
return this.fileProvider.moveFile(this.relativePath, newPath).then((fileEntry) => { return this.fileProvider.moveFile(this.relativePath, newPath).then((fileEntry) => {
this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, { this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, false,
form: this.formElement.nativeElement, this.sitesProvider.getCurrentSiteId());
online: false,
}, this.sitesProvider.getCurrentSiteId());
this.editMode = false; this.editMode = false;
this.file = fileEntry; this.file = fileEntry;

View File

@ -16,6 +16,7 @@ import { Component, Input, Output, EventEmitter, OnInit, ViewChild, ElementRef }
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { CoreEventsProvider } from '@providers/events'; import { CoreEventsProvider } from '@providers/events';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreUtilsProvider } from '@providers/utils/utils';
/** /**
@ -53,7 +54,8 @@ export class CoreSearchBoxComponent implements OnInit {
constructor(protected translate: TranslateService, constructor(protected translate: TranslateService,
protected utils: CoreUtilsProvider, protected utils: CoreUtilsProvider,
protected eventsProvider: CoreEventsProvider, protected eventsProvider: CoreEventsProvider,
protected sitesProvider: CoreSitesProvider) { protected sitesProvider: CoreSitesProvider,
protected domUtils: CoreDomUtilsProvider) {
this.onSubmit = new EventEmitter<string>(); this.onSubmit = new EventEmitter<string>();
this.onClear = new EventEmitter<void>(); this.onClear = new EventEmitter<void>();
} }
@ -80,10 +82,7 @@ export class CoreSearchBoxComponent implements OnInit {
return; return;
} }
this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, { this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, false, this.sitesProvider.getCurrentSiteId());
form: this.formElement.nativeElement,
online: false,
}, this.sitesProvider.getCurrentSiteId());
this.searched = true; this.searched = true;
this.onSubmit.emit(this.searchText); this.onSubmit.emit(this.searchText);

View File

@ -19,6 +19,7 @@ import { CoreEventsProvider } from '@providers/events';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider } from '@providers/sites';
import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreTextUtilsProvider } from '@providers/utils/text'; import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreConstants } from '@core/constants'; import { CoreConstants } from '@core/constants';
/** /**
@ -52,7 +53,8 @@ export class CoreSendMessageFormComponent implements OnInit {
configProvider: CoreConfigProvider, configProvider: CoreConfigProvider,
protected eventsProvider: CoreEventsProvider, protected eventsProvider: CoreEventsProvider,
protected sitesProvider: CoreSitesProvider, protected sitesProvider: CoreSitesProvider,
protected appProvider: CoreAppProvider) { protected appProvider: CoreAppProvider,
protected domUtils: CoreDomUtilsProvider) {
this.onSubmit = new EventEmitter(); this.onSubmit = new EventEmitter();
this.onResize = new EventEmitter(); this.onResize = new EventEmitter();
@ -88,10 +90,7 @@ export class CoreSendMessageFormComponent implements OnInit {
this.message = ''; // Reset the form. this.message = ''; // Reset the form.
this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, { this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, false, this.sitesProvider.getCurrentSiteId());
form: this.formElement.nativeElement,
online: false,
}, this.sitesProvider.getCurrentSiteId());
value = this.textUtils.replaceNewLines(value, '<br>'); value = this.textUtils.replaceNewLines(value, '<br>');
this.onSubmit.emit(value); this.onSubmit.emit(value);

View File

@ -71,10 +71,8 @@ export class CoreCommentsAddPage {
this.commentsProvider.addComment(this.content, this.contextLevel, this.instanceId, this.componentName, this.itemId, this.commentsProvider.addComment(this.content, this.contextLevel, this.instanceId, this.componentName, this.itemId,
this.area).then((commentsResponse) => { this.area).then((commentsResponse) => {
this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, { this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, !!commentsResponse,
form: this.formElement.nativeElement, this.sitesProvider.getCurrentSiteId());
online: !!commentsResponse,
}, this.sitesProvider.getCurrentSiteId());
this.viewCtrl.dismiss({comments: commentsResponse}).finally(() => { this.viewCtrl.dismiss({comments: commentsResponse}).finally(() => {
this.domUtils.showToast(commentsResponse ? 'core.comments.eventcommentcreated' : 'core.datastoredoffline', true, this.domUtils.showToast(commentsResponse ? 'core.comments.eventcommentcreated' : 'core.datastoredoffline', true,
@ -92,6 +90,7 @@ export class CoreCommentsAddPage {
* Close modal. * Close modal.
*/ */
closeModal(): void { closeModal(): void {
this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.sitesProvider.getCurrentSiteId());
this.viewCtrl.dismiss(); this.viewCtrl.dismiss();
} }
} }

View File

@ -16,6 +16,7 @@ import { Component, ViewChild, ElementRef } from '@angular/core';
import { IonicPage, ViewController } from 'ionic-angular'; import { IonicPage, ViewController } from 'ionic-angular';
import { CoreEventsProvider } from '@providers/events'; import { CoreEventsProvider } from '@providers/events';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
/** /**
* Page that displays a form to enter a password to self enrol in a course. * Page that displays a form to enter a password to self enrol in a course.
@ -31,12 +32,14 @@ export class CoreCoursesSelfEnrolPasswordPage {
constructor(protected viewCtrl: ViewController, constructor(protected viewCtrl: ViewController,
protected eventsProvider: CoreEventsProvider, protected eventsProvider: CoreEventsProvider,
protected sitesProvider: CoreSitesProvider) { } protected sitesProvider: CoreSitesProvider,
protected domUtils: CoreDomUtilsProvider) { }
/** /**
* Close help modal. * Close help modal.
*/ */
close(): void { close(): void {
this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.sitesProvider.getCurrentSiteId());
this.viewCtrl.dismiss(); this.viewCtrl.dismiss();
} }
@ -50,10 +53,7 @@ export class CoreCoursesSelfEnrolPasswordPage {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, { this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, false, this.sitesProvider.getCurrentSiteId());
form: this.formElement.nativeElement,
online: false,
}, this.sitesProvider.getCurrentSiteId());
this.viewCtrl.dismiss(password); this.viewCtrl.dismiss(password);
} }

View File

@ -194,7 +194,7 @@ export class CoreEditorRichTextEditorComponent implements AfterContentInit, OnDe
this.autoSaveDrafts(); this.autoSaveDrafts();
this.deleteDraftOnSubmit(); this.deleteDraftOnSubmitOrCancel();
} }
} }
@ -814,11 +814,11 @@ export class CoreEditorRichTextEditorComponent implements AfterContentInit, OnDe
} }
/** /**
* Delete the draft when the form is submitted. * Delete the draft when the form is submitted or cancelled.
*/ */
protected deleteDraftOnSubmit(): void { protected deleteDraftOnSubmitOrCancel(): void {
this.resetObs = this.events.on(CoreEventsProvider.FORM_SUBMITTED, async (data) => { this.resetObs = this.events.on(CoreEventsProvider.FORM_ACTION, async (data) => {
const form = this.element.closest('form'); const form = this.element.closest('form');
if (data.form && form && data.form == form) { if (data.form && form && data.form == form) {

View File

@ -246,10 +246,7 @@ export class CoreLoginCredentialsPage {
}).finally(() => { }).finally(() => {
modal.dismiss(); modal.dismiss();
this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, { this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, true);
form: this.formElement.nativeElement,
online: true,
});
}); });
} }

View File

@ -277,10 +277,7 @@ export class CoreLoginEmailSignupPage {
}).then((result) => { }).then((result) => {
if (result.success) { if (result.success) {
this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, { this.domUtils.triggerFormSubmittedEvent(this.signupFormElement.nativeElement, true);
form: this.signupFormElement.nativeElement,
online: true,
});
// Show alert and ho back. // Show alert and ho back.
const message = this.translate.instant('core.login.emailconfirmsent', { $a: params.email }); const message = this.translate.instant('core.login.emailconfirmsent', { $a: params.email });
@ -352,10 +349,7 @@ export class CoreLoginEmailSignupPage {
this.wsProvider.callAjax('core_auth_is_minor', params, {siteUrl: this.siteUrl}).then((result) => { this.wsProvider.callAjax('core_auth_is_minor', params, {siteUrl: this.siteUrl}).then((result) => {
this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, { this.domUtils.triggerFormSubmittedEvent(this.ageFormElement.nativeElement, true);
form: this.ageFormElement.nativeElement,
online: true,
});
if (!result.status) { if (!result.status) {
if (this.countryControl.value) { if (this.countryControl.value) {

View File

@ -82,10 +82,7 @@ export class CoreLoginForgottenPasswordPage {
this.domUtils.showErrorModal(response.notice); this.domUtils.showErrorModal(response.notice);
} else { } else {
// Success. // Success.
this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, { this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, true);
form: this.formElement.nativeElement,
online: true,
});
this.domUtils.showAlert(this.translate.instant('core.success'), response.notice); this.domUtils.showAlert(this.translate.instant('core.success'), response.notice);
this.navCtrl.pop(); this.navCtrl.pop();

View File

@ -181,10 +181,7 @@ export class CoreLoginReconnectPage {
this.sitesProvider.getUserToken(siteUrl, username, password).then((data) => { this.sitesProvider.getUserToken(siteUrl, username, password).then((data) => {
return this.sitesProvider.updateSiteToken(this.infoSiteUrl, username, data.token, data.privateToken).then(() => { return this.sitesProvider.updateSiteToken(this.infoSiteUrl, username, data.token, data.privateToken).then(() => {
this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, { this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, true);
form: this.formElement.nativeElement,
online: true,
});
// Update site info too because functions might have changed (e.g. unisntall local_mobile). // Update site info too because functions might have changed (e.g. unisntall local_mobile).
return this.sitesProvider.updateSiteInfoByUrl(this.infoSiteUrl, username).then(() => { return this.sitesProvider.updateSiteInfoByUrl(this.infoSiteUrl, username).then(() => {

View File

@ -107,10 +107,7 @@ export class CoreLoginSitePage {
this.sitesProvider.getUserToken(siteData.url, siteData.username, siteData.password).then((data) => { this.sitesProvider.getUserToken(siteData.url, siteData.username, siteData.password).then((data) => {
return this.sitesProvider.newSite(data.siteUrl, data.token, data.privateToken).then(() => { return this.sitesProvider.newSite(data.siteUrl, data.token, data.privateToken).then(() => {
this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, { this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, true);
form: this.formElement.nativeElement,
online: true,
});
return this.loginHelper.goToSiteInitialPage(); return this.loginHelper.goToSiteInitialPage();
}, (error) => { }, (error) => {
@ -192,10 +189,7 @@ export class CoreLoginSitePage {
protected async login(response: CoreSiteCheckResponse): Promise<void> { protected async login(response: CoreSiteCheckResponse): Promise<void> {
return this.sitesProvider.checkRequiredMinimumVersion(response.config).then(() => { return this.sitesProvider.checkRequiredMinimumVersion(response.config).then(() => {
this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, { this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, true);
form: this.formElement.nativeElement,
online: true,
});
if (response.warning) { if (response.warning) {
this.domUtils.showErrorModal(response.warning, true, 4000); this.domUtils.showErrorModal(response.warning, true, 4000);

View File

@ -64,7 +64,7 @@ export class CoreEventsProvider {
static SELECT_COURSE_TAB = 'select_course_tab'; static SELECT_COURSE_TAB = 'select_course_tab';
static WS_CACHE_INVALIDATED = 'ws_cache_invalidated'; static WS_CACHE_INVALIDATED = 'ws_cache_invalidated';
static SITE_STORAGE_DELETED = 'site_storage_deleted'; static SITE_STORAGE_DELETED = 'site_storage_deleted';
static FORM_SUBMITTED = 'form_submitted'; static FORM_ACTION = 'form_action';
protected logger; protected logger;
protected observables: { [s: string]: Subject<any> } = {}; protected observables: { [s: string]: Subject<any> } = {};

View File

@ -22,6 +22,7 @@ import { TranslateService } from '@ngx-translate/core';
import { CoreTextUtilsProvider } from './text'; import { CoreTextUtilsProvider } from './text';
import { CoreAppProvider } from '../app'; import { CoreAppProvider } from '../app';
import { CoreConfigProvider } from '../config'; import { CoreConfigProvider } from '../config';
import { CoreEventsProvider } from '../events';
import { CoreLoggerProvider } from '../logger'; import { CoreLoggerProvider } from '../logger';
import { CoreUrlUtilsProvider } from './url'; import { CoreUrlUtilsProvider } from './url';
import { CoreFileProvider } from '@providers/file'; import { CoreFileProvider } from '@providers/file';
@ -64,20 +65,21 @@ export class CoreDomUtilsProvider {
protected displayedAlerts = {}; // To prevent duplicated alerts. protected displayedAlerts = {}; // To prevent duplicated alerts.
protected logger; protected logger;
constructor(private translate: TranslateService, constructor(protected translate: TranslateService,
private loadingCtrl: LoadingController, protected loadingCtrl: LoadingController,
private toastCtrl: ToastController, protected toastCtrl: ToastController,
private alertCtrl: AlertController, protected alertCtrl: AlertController,
private textUtils: CoreTextUtilsProvider, protected textUtils: CoreTextUtilsProvider,
private appProvider: CoreAppProvider, protected appProvider: CoreAppProvider,
private platform: Platform, protected platform: Platform,
private configProvider: CoreConfigProvider, protected configProvider: CoreConfigProvider,
private urlUtils: CoreUrlUtilsProvider, protected urlUtils: CoreUrlUtilsProvider,
private modalCtrl: ModalController, protected modalCtrl: ModalController,
private sanitizer: DomSanitizer, protected sanitizer: DomSanitizer,
private popoverCtrl: PopoverController, protected popoverCtrl: PopoverController,
private fileProvider: CoreFileProvider, protected fileProvider: CoreFileProvider,
loggerProvider: CoreLoggerProvider) { loggerProvider: CoreLoggerProvider,
protected eventsProvider: CoreEventsProvider) {
this.logger = loggerProvider.getInstance('CoreDomUtilsProvider'); this.logger = loggerProvider.getInstance('CoreDomUtilsProvider');
@ -1625,4 +1627,32 @@ export class CoreDomUtilsProvider {
// Now move the element into the wrapper. // Now move the element into the wrapper.
wrapper.appendChild(el); wrapper.appendChild(el);
} }
/**
* Trigger form cancelled event.
*
* @param form Form element.
* @param siteId The site affected. If not provided, no site affected.
*/
triggerFormCancelledEvent(form: HTMLElement, siteId?: string): void {
this.eventsProvider.trigger(CoreEventsProvider.FORM_ACTION, {
action: 'cancel',
form: form,
}, siteId);
}
/**
* Trigger form submitted event.
*
* @param form Form element.
* @param online Whether the action was done in offline or not.
* @param siteId The site affected. If not provided, no site affected.
*/
triggerFormSubmittedEvent(form: HTMLElement, online?: boolean, siteId?: string): void {
this.eventsProvider.trigger(CoreEventsProvider.FORM_ACTION, {
action: 'submit',
form: form,
online: !!online,
}, siteId);
}
} }