From 96c862260851852dc02b44f17177b75681bcc4a0 Mon Sep 17 00:00:00 2001
From: Dani Palou
Date: Tue, 28 Jan 2020 12:52:56 +0100
Subject: [PATCH 1/9] MOBILE-3323 editor: Create new folder editor in src/core
---
.../pages/edit-event/edit-event.module.ts | 2 +
.../calendar/pages/edit-event/edit-event.ts | 4 +-
.../feedback/comments/comments.module.ts | 4 +-
.../onlinetext/onlinetext.module.ts | 4 +-
src/addon/mod/data/fields/field.module.ts | 2 +-
.../data/fields/textarea/textarea.module.ts | 4 +-
.../mod/forum/components/components.module.ts | 4 +-
.../forum/pages/edit-post/edit-post.module.ts | 2 +
.../new-discussion/new-discussion.module.ts | 2 +
.../pages/new-discussion/new-discussion.ts | 4 +-
.../mod/glossary/pages/edit/edit.module.ts | 2 +
.../mod/lesson/pages/player/player.module.ts | 2 +
src/addon/mod/wiki/pages/edit/edit.module.ts | 2 +
.../workshop/components/components.module.ts | 4 +-
.../pages/assessment/assessment.module.ts | 2 +
.../edit-submission/edit-submission.module.ts | 2 +
.../pages/submission/submission.module.ts | 2 +
src/addon/qtype/essay/essay.module.ts | 4 +-
.../textarea/textarea.module.ts | 4 +-
src/app/app.module.ts | 2 +
src/components/components.module.ts | 3 --
.../editor/components/components.module.ts | 41 +++++++++++++++++++
.../core-editor-rich-text-editor.html} | 0
.../rich-text-editor/rich-text-editor.scss | 0
.../rich-text-editor/rich-text-editor.ts | 14 ++-----
src/core/editor/editor.module.ts | 27 ++++++++++++
26 files changed, 118 insertions(+), 25 deletions(-)
create mode 100644 src/core/editor/components/components.module.ts
rename src/{components/rich-text-editor/core-rich-text-editor.html => core/editor/components/rich-text-editor/core-editor-rich-text-editor.html} (100%)
rename src/{ => core/editor}/components/rich-text-editor/rich-text-editor.scss (100%)
rename src/{ => core/editor}/components/rich-text-editor/rich-text-editor.ts (97%)
create mode 100644 src/core/editor/editor.module.ts
diff --git a/src/addon/calendar/pages/edit-event/edit-event.module.ts b/src/addon/calendar/pages/edit-event/edit-event.module.ts
index 32a1ac65ae1..5821de8a0fb 100644
--- a/src/addon/calendar/pages/edit-event/edit-event.module.ts
+++ b/src/addon/calendar/pages/edit-event/edit-event.module.ts
@@ -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({
@@ -26,6 +27,7 @@ import { AddonCalendarEditEventPage } from './edit-event';
imports: [
CoreComponentsModule,
CoreDirectivesModule,
+ CoreEditorComponentsModule,
IonicPageModule.forChild(AddonCalendarEditEventPage),
TranslateModule.forChild()
],
diff --git a/src/addon/calendar/pages/edit-event/edit-event.ts b/src/addon/calendar/pages/edit-event/edit-event.ts
index 293d1fd6291..16f9350ce48 100644
--- a/src/addon/calendar/pages/edit-event/edit-event.ts
+++ b/src/addon/calendar/pages/edit-event/edit-event.ts
@@ -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';
@@ -43,7 +43,7 @@ import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
})
export class AddonCalendarEditEventPage implements OnInit, OnDestroy {
- @ViewChild(CoreRichTextEditorComponent) descriptionEditor: CoreRichTextEditorComponent;
+ @ViewChild(CoreEditorRichTextEditorComponent) descriptionEditor: CoreEditorRichTextEditorComponent;
title: string;
dateFormat: string;
diff --git a/src/addon/mod/assign/feedback/comments/comments.module.ts b/src/addon/mod/assign/feedback/comments/comments.module.ts
index 491a88fde52..cb23c6983b7 100644
--- a/src/addon/mod/assign/feedback/comments/comments.module.ts
+++ b/src/addon/mod/assign/feedback/comments/comments.module.ts
@@ -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: [
@@ -31,7 +32,8 @@ import { CoreDirectivesModule } from '@directives/directives.module';
IonicModule,
TranslateModule.forChild(),
CoreComponentsModule,
- CoreDirectivesModule
+ CoreDirectivesModule,
+ CoreEditorComponentsModule,
],
providers: [
AddonModAssignFeedbackCommentsHandler
diff --git a/src/addon/mod/assign/submission/onlinetext/onlinetext.module.ts b/src/addon/mod/assign/submission/onlinetext/onlinetext.module.ts
index 88de4de1d4e..5ac1e16f827 100644
--- a/src/addon/mod/assign/submission/onlinetext/onlinetext.module.ts
+++ b/src/addon/mod/assign/submission/onlinetext/onlinetext.module.ts
@@ -21,6 +21,7 @@ import { AddonModAssignSubmissionOnlineTextComponent } from './component/onlinet
import { AddonModAssignSubmissionDelegate } from '../../providers/submission-delegate';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
+import { CoreEditorComponentsModule } from '@core/editor/components/components.module';
@NgModule({
declarations: [
@@ -31,7 +32,8 @@ import { CoreDirectivesModule } from '@directives/directives.module';
IonicModule,
TranslateModule.forChild(),
CoreComponentsModule,
- CoreDirectivesModule
+ CoreDirectivesModule,
+ CoreEditorComponentsModule,
],
providers: [
AddonModAssignSubmissionOnlineTextHandler
diff --git a/src/addon/mod/data/fields/field.module.ts b/src/addon/mod/data/fields/field.module.ts
index 0e0467799d4..9a850d4f6cd 100644
--- a/src/addon/mod/data/fields/field.module.ts
+++ b/src/addon/mod/data/fields/field.module.ts
@@ -40,7 +40,7 @@ import { AddonModDataFieldUrlModule } from './url/url.module';
AddonModDataFieldRadiobuttonModule,
AddonModDataFieldTextModule,
AddonModDataFieldTextareaModule,
- AddonModDataFieldUrlModule
+ AddonModDataFieldUrlModule,
],
providers: [
],
diff --git a/src/addon/mod/data/fields/textarea/textarea.module.ts b/src/addon/mod/data/fields/textarea/textarea.module.ts
index 3f7070ef730..ead1184b6ae 100644
--- a/src/addon/mod/data/fields/textarea/textarea.module.ts
+++ b/src/addon/mod/data/fields/textarea/textarea.module.ts
@@ -20,6 +20,7 @@ import { AddonModDataFieldsDelegate } from '../../providers/fields-delegate';
import { AddonModDataFieldTextareaComponent } from './component/textarea';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
+import { CoreEditorComponentsModule } from '@core/editor/components/components.module';
@NgModule({
declarations: [
@@ -30,7 +31,8 @@ import { CoreDirectivesModule } from '@directives/directives.module';
IonicModule,
TranslateModule.forChild(),
CoreComponentsModule,
- CoreDirectivesModule
+ CoreDirectivesModule,
+ CoreEditorComponentsModule,
],
providers: [
AddonModDataFieldTextareaHandler
diff --git a/src/addon/mod/forum/components/components.module.ts b/src/addon/mod/forum/components/components.module.ts
index 5a3180af3ca..e9cdcba1498 100644
--- a/src/addon/mod/forum/components/components.module.ts
+++ b/src/addon/mod/forum/components/components.module.ts
@@ -26,6 +26,7 @@ import { AddonModForumIndexComponent } from './index/index';
import { AddonModForumPostComponent } from './post/post';
import { AddonForumDiscussionOptionsMenuComponent } from './discussion-options-menu/discussion-options-menu';
import { AddonForumPostOptionsMenuComponent } from './post-options-menu/post-options-menu';
+import { CoreEditorComponentsModule } from '@core/editor/components/components.module';
@NgModule({
declarations: [
@@ -43,7 +44,8 @@ import { AddonForumPostOptionsMenuComponent } from './post-options-menu/post-opt
CorePipesModule,
CoreCourseComponentsModule,
CoreRatingComponentsModule,
- CoreTagComponentsModule
+ CoreTagComponentsModule,
+ CoreEditorComponentsModule,
],
providers: [
],
diff --git a/src/addon/mod/forum/pages/edit-post/edit-post.module.ts b/src/addon/mod/forum/pages/edit-post/edit-post.module.ts
index 07f4097427a..89cf9ad4d66 100644
--- a/src/addon/mod/forum/pages/edit-post/edit-post.module.ts
+++ b/src/addon/mod/forum/pages/edit-post/edit-post.module.ts
@@ -19,6 +19,7 @@ import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
import { AddonModForumComponentsModule } from '../../components/components.module';
import { AddonModForumEditPostPage } from './edit-post';
+import { CoreEditorComponentsModule } from '@core/editor/components/components.module';
@NgModule({
declarations: [
@@ -28,6 +29,7 @@ import { AddonModForumEditPostPage } from './edit-post';
CoreComponentsModule,
CoreDirectivesModule,
AddonModForumComponentsModule,
+ CoreEditorComponentsModule,
IonicPageModule.forChild(AddonModForumEditPostPage),
TranslateModule.forChild()
],
diff --git a/src/addon/mod/forum/pages/new-discussion/new-discussion.module.ts b/src/addon/mod/forum/pages/new-discussion/new-discussion.module.ts
index c0add2f4c10..0bb9e40386d 100644
--- a/src/addon/mod/forum/pages/new-discussion/new-discussion.module.ts
+++ b/src/addon/mod/forum/pages/new-discussion/new-discussion.module.ts
@@ -18,6 +18,7 @@ import { TranslateModule } from '@ngx-translate/core';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
import { AddonModForumNewDiscussionPage } from './new-discussion';
+import { CoreEditorComponentsModule } from '@core/editor/components/components.module';
@NgModule({
declarations: [
@@ -26,6 +27,7 @@ import { AddonModForumNewDiscussionPage } from './new-discussion';
imports: [
CoreComponentsModule,
CoreDirectivesModule,
+ CoreEditorComponentsModule,
IonicPageModule.forChild(AddonModForumNewDiscussionPage),
TranslateModule.forChild()
],
diff --git a/src/addon/mod/forum/pages/new-discussion/new-discussion.ts b/src/addon/mod/forum/pages/new-discussion/new-discussion.ts
index 09175386588..68b44837bca 100644
--- a/src/addon/mod/forum/pages/new-discussion/new-discussion.ts
+++ b/src/addon/mod/forum/pages/new-discussion/new-discussion.ts
@@ -25,7 +25,7 @@ import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreFileUploaderProvider } from '@core/fileuploader/providers/fileuploader';
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 { AddonModForumProvider } from '../../providers/forum';
import { AddonModForumOfflineProvider } from '../../providers/offline';
import { AddonModForumHelperProvider } from '../../providers/helper';
@@ -41,7 +41,7 @@ import { AddonModForumSyncProvider } from '../../providers/sync';
})
export class AddonModForumNewDiscussionPage implements OnDestroy {
- @ViewChild(CoreRichTextEditorComponent) messageEditor: CoreRichTextEditorComponent;
+ @ViewChild(CoreEditorRichTextEditorComponent) messageEditor: CoreEditorRichTextEditorComponent;
component = AddonModForumProvider.COMPONENT;
messageControl = new FormControl();
diff --git a/src/addon/mod/glossary/pages/edit/edit.module.ts b/src/addon/mod/glossary/pages/edit/edit.module.ts
index 0f606e93ecb..926f32ad6bd 100644
--- a/src/addon/mod/glossary/pages/edit/edit.module.ts
+++ b/src/addon/mod/glossary/pages/edit/edit.module.ts
@@ -18,6 +18,7 @@ import { TranslateModule } from '@ngx-translate/core';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
import { AddonModGlossaryEditPage } from './edit';
+import { CoreEditorComponentsModule } from '@core/editor/components/components.module';
@NgModule({
declarations: [
@@ -26,6 +27,7 @@ import { AddonModGlossaryEditPage } from './edit';
imports: [
CoreComponentsModule,
CoreDirectivesModule,
+ CoreEditorComponentsModule,
IonicPageModule.forChild(AddonModGlossaryEditPage),
TranslateModule.forChild()
],
diff --git a/src/addon/mod/lesson/pages/player/player.module.ts b/src/addon/mod/lesson/pages/player/player.module.ts
index 361ae19ab1f..c6dd3509735 100644
--- a/src/addon/mod/lesson/pages/player/player.module.ts
+++ b/src/addon/mod/lesson/pages/player/player.module.ts
@@ -18,6 +18,7 @@ import { TranslateModule } from '@ngx-translate/core';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
import { AddonModLessonPlayerPage } from './player';
+import { CoreEditorComponentsModule } from '@core/editor/components/components.module';
@NgModule({
declarations: [
@@ -26,6 +27,7 @@ import { AddonModLessonPlayerPage } from './player';
imports: [
CoreComponentsModule,
CoreDirectivesModule,
+ CoreEditorComponentsModule,
IonicPageModule.forChild(AddonModLessonPlayerPage),
TranslateModule.forChild()
],
diff --git a/src/addon/mod/wiki/pages/edit/edit.module.ts b/src/addon/mod/wiki/pages/edit/edit.module.ts
index 20b25f6bc88..ecf4b0fa49e 100644
--- a/src/addon/mod/wiki/pages/edit/edit.module.ts
+++ b/src/addon/mod/wiki/pages/edit/edit.module.ts
@@ -18,6 +18,7 @@ import { TranslateModule } from '@ngx-translate/core';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
import { AddonModWikiEditPage } from './edit';
+import { CoreEditorComponentsModule } from '@core/editor/components/components.module';
@NgModule({
declarations: [
@@ -26,6 +27,7 @@ import { AddonModWikiEditPage } from './edit';
imports: [
CoreComponentsModule,
CoreDirectivesModule,
+ CoreEditorComponentsModule,
IonicPageModule.forChild(AddonModWikiEditPage),
TranslateModule.forChild()
],
diff --git a/src/addon/mod/workshop/components/components.module.ts b/src/addon/mod/workshop/components/components.module.ts
index 77549039667..279484ef6e2 100644
--- a/src/addon/mod/workshop/components/components.module.ts
+++ b/src/addon/mod/workshop/components/components.module.ts
@@ -24,6 +24,7 @@ import { AddonModWorkshopIndexComponent } from './index/index';
import { AddonModWorkshopSubmissionComponent } from './submission/submission';
import { AddonModWorkshopAssessmentComponent } from './assessment/assessment';
import { AddonModWorkshopAssessmentStrategyComponent } from './assessment-strategy/assessment-strategy';
+import { CoreEditorComponentsModule } from '@core/editor/components/components.module';
@NgModule({
declarations: [
@@ -39,7 +40,8 @@ import { AddonModWorkshopAssessmentStrategyComponent } from './assessment-strate
CoreComponentsModule,
CoreDirectivesModule,
CorePipesModule,
- CoreCourseComponentsModule
+ CoreCourseComponentsModule,
+ CoreEditorComponentsModule,
],
providers: [
],
diff --git a/src/addon/mod/workshop/pages/assessment/assessment.module.ts b/src/addon/mod/workshop/pages/assessment/assessment.module.ts
index 21415631eda..8a2314b3448 100644
--- a/src/addon/mod/workshop/pages/assessment/assessment.module.ts
+++ b/src/addon/mod/workshop/pages/assessment/assessment.module.ts
@@ -19,6 +19,7 @@ import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
import { AddonModWorkshopComponentsModule } from '../../components/components.module';
import { AddonModWorkshopAssessmentPage } from './assessment';
+import { CoreEditorComponentsModule } from '@core/editor/components/components.module';
@NgModule({
declarations: [
@@ -28,6 +29,7 @@ import { AddonModWorkshopAssessmentPage } from './assessment';
CoreDirectivesModule,
CoreComponentsModule,
AddonModWorkshopComponentsModule,
+ CoreEditorComponentsModule,
IonicPageModule.forChild(AddonModWorkshopAssessmentPage),
TranslateModule.forChild()
],
diff --git a/src/addon/mod/workshop/pages/edit-submission/edit-submission.module.ts b/src/addon/mod/workshop/pages/edit-submission/edit-submission.module.ts
index 25e5e407368..d3b216c6083 100644
--- a/src/addon/mod/workshop/pages/edit-submission/edit-submission.module.ts
+++ b/src/addon/mod/workshop/pages/edit-submission/edit-submission.module.ts
@@ -18,6 +18,7 @@ import { TranslateModule } from '@ngx-translate/core';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
import { AddonModWorkshopEditSubmissionPage } from './edit-submission';
+import { CoreEditorComponentsModule } from '@core/editor/components/components.module';
@NgModule({
declarations: [
@@ -26,6 +27,7 @@ import { AddonModWorkshopEditSubmissionPage } from './edit-submission';
imports: [
CoreDirectivesModule,
CoreComponentsModule,
+ CoreEditorComponentsModule,
IonicPageModule.forChild(AddonModWorkshopEditSubmissionPage),
TranslateModule.forChild()
],
diff --git a/src/addon/mod/workshop/pages/submission/submission.module.ts b/src/addon/mod/workshop/pages/submission/submission.module.ts
index b393b059b0f..6484fdc0645 100644
--- a/src/addon/mod/workshop/pages/submission/submission.module.ts
+++ b/src/addon/mod/workshop/pages/submission/submission.module.ts
@@ -19,6 +19,7 @@ import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
import { AddonModWorkshopComponentsModule } from '../../components/components.module';
import { AddonModWorkshopSubmissionPage } from './submission';
+import { CoreEditorComponentsModule } from '@core/editor/components/components.module';
@NgModule({
declarations: [
@@ -28,6 +29,7 @@ import { AddonModWorkshopSubmissionPage } from './submission';
CoreDirectivesModule,
CoreComponentsModule,
AddonModWorkshopComponentsModule,
+ CoreEditorComponentsModule,
IonicPageModule.forChild(AddonModWorkshopSubmissionPage),
TranslateModule.forChild()
],
diff --git a/src/addon/qtype/essay/essay.module.ts b/src/addon/qtype/essay/essay.module.ts
index da95a136343..d259137cc8c 100644
--- a/src/addon/qtype/essay/essay.module.ts
+++ b/src/addon/qtype/essay/essay.module.ts
@@ -20,6 +20,7 @@ import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
import { AddonQtypeEssayHandler } from './providers/handler';
import { AddonQtypeEssayComponent } from './component/essay';
+import { CoreEditorComponentsModule } from '@core/editor/components/components.module';
@NgModule({
declarations: [
@@ -29,7 +30,8 @@ import { AddonQtypeEssayComponent } from './component/essay';
IonicModule,
TranslateModule.forChild(),
CoreComponentsModule,
- CoreDirectivesModule
+ CoreDirectivesModule,
+ CoreEditorComponentsModule,
],
providers: [
AddonQtypeEssayHandler
diff --git a/src/addon/userprofilefield/textarea/textarea.module.ts b/src/addon/userprofilefield/textarea/textarea.module.ts
index f64fc285de6..68ad0e67836 100644
--- a/src/addon/userprofilefield/textarea/textarea.module.ts
+++ b/src/addon/userprofilefield/textarea/textarea.module.ts
@@ -20,6 +20,7 @@ import { CoreUserProfileFieldDelegate } from '@core/user/providers/user-profile-
import { AddonUserProfileFieldTextareaComponent } from './component/textarea';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
+import { CoreEditorComponentsModule } from '@core/editor/components/components.module';
@NgModule({
declarations: [
@@ -29,7 +30,8 @@ import { CoreDirectivesModule } from '@directives/directives.module';
IonicModule,
TranslateModule.forChild(),
CoreComponentsModule,
- CoreDirectivesModule
+ CoreDirectivesModule,
+ CoreEditorComponentsModule,
],
providers: [
AddonUserProfileFieldTextareaHandler
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 38fff7b5d95..81fdb84a790 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -87,6 +87,7 @@ import { CoreTagModule } from '@core/tag/tag.module';
import { CoreFilterModule } from '@core/filter/filter.module';
import { CoreH5PModule } from '@core/h5p/h5p.module';
import { CoreSearchModule } from '@core/search/search.module';
+import { CoreEditorModule } from '@core/editor/editor.module';
// Addon modules.
import { AddonBadgesModule } from '@addon/badges/badges.module';
@@ -235,6 +236,7 @@ export const WP_PROVIDER: any = null;
CoreFilterModule,
CoreH5PModule,
CoreSearchModule,
+ CoreEditorModule,
AddonBadgesModule,
AddonBlogModule,
AddonCalendarModule,
diff --git a/src/components/components.module.ts b/src/components/components.module.ts
index bdd2f6d4c52..e48f29dd673 100644
--- a/src/components/components.module.ts
+++ b/src/components/components.module.ts
@@ -39,7 +39,6 @@ import { CoreLocalFileComponent } from './local-file/local-file';
import { CoreSitePickerComponent } from './site-picker/site-picker';
import { CoreTabsComponent } from './tabs/tabs';
import { CoreTabComponent } from './tabs/tab';
-import { CoreRichTextEditorComponent } from './rich-text-editor/rich-text-editor';
import { CoreNavBarButtonsComponent } from './navbar-buttons/navbar-buttons';
import { CoreDynamicComponent } from './dynamic-component/dynamic-component';
import { CoreSendMessageFormComponent } from './send-message-form/send-message-form';
@@ -79,7 +78,6 @@ import { CoreBSTooltipComponent } from './bs-tooltip/bs-tooltip';
CoreSitePickerComponent,
CoreTabsComponent,
CoreTabComponent,
- CoreRichTextEditorComponent,
CoreNavBarButtonsComponent,
CoreDynamicComponent,
CoreSendMessageFormComponent,
@@ -128,7 +126,6 @@ import { CoreBSTooltipComponent } from './bs-tooltip/bs-tooltip';
CoreSitePickerComponent,
CoreTabsComponent,
CoreTabComponent,
- CoreRichTextEditorComponent,
CoreNavBarButtonsComponent,
CoreDynamicComponent,
CoreSendMessageFormComponent,
diff --git a/src/core/editor/components/components.module.ts b/src/core/editor/components/components.module.ts
new file mode 100644
index 00000000000..5d8edf3e7e8
--- /dev/null
+++ b/src/core/editor/components/components.module.ts
@@ -0,0 +1,41 @@
+// (C) Copyright 2015 Moodle Pty Ltd.
+//
+// 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 { CoreEditorRichTextEditorComponent } from './rich-text-editor/rich-text-editor';
+import { CoreComponentsModule } from '@components/components.module';
+
+@NgModule({
+ declarations: [
+ CoreEditorRichTextEditorComponent
+ ],
+ imports: [
+ CommonModule,
+ IonicModule,
+ TranslateModule.forChild(),
+ CoreComponentsModule,
+ ],
+ providers: [
+ ],
+ exports: [
+ CoreEditorRichTextEditorComponent
+ ],
+ entryComponents: [
+ CoreEditorRichTextEditorComponent
+ ]
+})
+export class CoreEditorComponentsModule {}
diff --git a/src/components/rich-text-editor/core-rich-text-editor.html b/src/core/editor/components/rich-text-editor/core-editor-rich-text-editor.html
similarity index 100%
rename from src/components/rich-text-editor/core-rich-text-editor.html
rename to src/core/editor/components/rich-text-editor/core-editor-rich-text-editor.html
diff --git a/src/components/rich-text-editor/rich-text-editor.scss b/src/core/editor/components/rich-text-editor/rich-text-editor.scss
similarity index 100%
rename from src/components/rich-text-editor/rich-text-editor.scss
rename to src/core/editor/components/rich-text-editor/rich-text-editor.scss
diff --git a/src/components/rich-text-editor/rich-text-editor.ts b/src/core/editor/components/rich-text-editor/rich-text-editor.ts
similarity index 97%
rename from src/components/rich-text-editor/rich-text-editor.ts
rename to src/core/editor/components/rich-text-editor/rich-text-editor.ts
index d4367e509db..8520959c5d6 100644
--- a/src/components/rich-text-editor/rich-text-editor.ts
+++ b/src/core/editor/components/rich-text-editor/rich-text-editor.ts
@@ -25,24 +25,18 @@ import { FormControl } from '@angular/forms';
import { Subscription } from 'rxjs';
/**
- * Directive to display a rich text editor if enabled.
+ * Component to display a rich text editor if enabled.
*
- * If enabled, this directive will show a rich text editor. Otherwise it'll show a regular textarea.
- *
- * This directive requires an OBJECT model. The text written in the editor or textarea will be stored inside
- * a "text" property in that object. This is to ensure 2-way data-binding, since using a string as a model
- * could be easily broken.
+ * If enabled, this component will show a rich text editor. Otherwise it'll show a regular textarea.
*
* Example:
*
- *
- * In the example above, the text written in the editor will be stored in newpost.text.
*/
@Component({
selector: 'core-rich-text-editor',
- templateUrl: 'core-rich-text-editor.html'
+ templateUrl: 'core-editor-rich-text-editor.html'
})
-export class CoreRichTextEditorComponent implements AfterContentInit, OnDestroy {
+export class CoreEditorRichTextEditorComponent implements AfterContentInit, OnDestroy {
// Based on: https://github.com/judgewest2000/Ionic3RichText/
// @todo: Anchor button, fullscreen...
// @todo: Textarea height is not being updated when editor is resized. Height is calculated if any css is changed.
diff --git a/src/core/editor/editor.module.ts b/src/core/editor/editor.module.ts
new file mode 100644
index 00000000000..1052cfb8bdb
--- /dev/null
+++ b/src/core/editor/editor.module.ts
@@ -0,0 +1,27 @@
+// (C) Copyright 2015 Moodle Pty Ltd.
+//
+// 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 { CoreEditorComponentsModule } from './components/components.module';
+
+@NgModule({
+ declarations: [
+ ],
+ imports: [
+ CoreEditorComponentsModule
+ ],
+ providers: [
+ ]
+})
+export class CoreEditorModule {}
From d2f4df452e56cd02db42df3681a52e65aa86cd20 Mon Sep 17 00:00:00 2001
From: Dani Palou
Date: Tue, 28 Jan 2020 17:57:41 +0100
Subject: [PATCH 2/9] MOBILE-3323 editor: Create offline provider for editor
---
src/core/editor/editor.module.ts | 17 +-
src/core/editor/providers/editor-offline.ts | 254 ++++++++++++++++++++
2 files changed, 268 insertions(+), 3 deletions(-)
create mode 100644 src/core/editor/providers/editor-offline.ts
diff --git a/src/core/editor/editor.module.ts b/src/core/editor/editor.module.ts
index 1052cfb8bdb..e55c88a493c 100644
--- a/src/core/editor/editor.module.ts
+++ b/src/core/editor/editor.module.ts
@@ -14,14 +14,25 @@
import { NgModule } from '@angular/core';
import { CoreEditorComponentsModule } from './components/components.module';
+import { CoreEditorOfflineProvider } from './providers/editor-offline';
+
+// List of providers (without handlers).
+export const CORE_GRADES_PROVIDERS: any[] = [
+ CoreEditorOfflineProvider,
+];
@NgModule({
declarations: [
],
imports: [
- CoreEditorComponentsModule
+ CoreEditorComponentsModule,
],
providers: [
- ]
+ CoreEditorOfflineProvider,
+ ],
})
-export class CoreEditorModule {}
+export class CoreEditorModule {
+ constructor(editorOffline: CoreEditorOfflineProvider) {
+ // Inject the helper even if it isn't used here it's instantiated.
+ }
+}
diff --git a/src/core/editor/providers/editor-offline.ts b/src/core/editor/providers/editor-offline.ts
new file mode 100644
index 00000000000..0f0b5e28cbf
--- /dev/null
+++ b/src/core/editor/providers/editor-offline.ts
@@ -0,0 +1,254 @@
+// (C) Copyright 2015 Moodle Pty Ltd.
+//
+// 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 { CoreLoggerProvider } from '@providers/logger';
+import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
+import { CoreTextUtilsProvider } from '@providers/utils/text';
+import { CoreUtilsProvider } from '@providers/utils/utils';
+
+/**
+ * Service with features regarding rich text editor in offline.
+ */
+@Injectable()
+export class CoreEditorOfflineProvider {
+
+ protected DRAFT_TABLE = 'editor_draft';
+
+ protected logger;
+ protected siteSchema: CoreSiteSchema = {
+ name: 'CoreEditorProvider',
+ version: 1,
+ tables: [
+ {
+ name: this.DRAFT_TABLE,
+ columns: [
+ {
+ name: 'contextlevel',
+ type: 'TEXT',
+ },
+ {
+ name: 'contextinstanceid',
+ type: 'INTEGER',
+ },
+ {
+ name: 'elementid',
+ type: 'TEXT',
+ },
+ {
+ name: 'extraparams', // Moodle web uses a page hash built with URL. App will use some params stringified.
+ type: 'TEXT',
+ },
+ {
+ name: 'drafttext',
+ type: 'TEXT',
+ notNull: true
+ },
+ {
+ name: 'pageinstance',
+ type: 'TEXT',
+ notNull: true
+ },
+ {
+ name: 'timecreated',
+ type: 'INTEGER',
+ notNull: true
+ },
+ {
+ name: 'timemodified',
+ type: 'INTEGER',
+ notNull: true
+ },
+ ],
+ primaryKeys: ['contextlevel', 'contextinstanceid', 'elementid', 'extraparams']
+ },
+ ],
+ };
+
+ constructor(
+ logger: CoreLoggerProvider,
+ protected sitesProvider: CoreSitesProvider,
+ protected textUtils: CoreTextUtilsProvider,
+ protected utils: CoreUtilsProvider) {
+ this.logger = logger.getInstance('CoreEditorProvider');
+
+ this.sitesProvider.registerSiteSchema(this.siteSchema);
+ }
+
+ /**
+ * Delete a draft from DB.
+ *
+ * @param contextLevel Context level.
+ * @param contextInstanceId The instance ID related to the context.
+ * @param elementId Element ID.
+ * @param extraParams Object with extra params to identify the draft.
+ * @param siteId Site ID. If not defined, current site.
+ * @return Promise resolved when done.
+ */
+ async deleteDraft(contextLevel: string, contextInstanceId: number, elementId: string, extraParams: {[name: string]: any},
+ siteId?: string): Promise {
+
+ try {
+ const db = await this.sitesProvider.getSiteDb(siteId);
+
+ const params = this.fixDraftPrimaryData(contextLevel, contextInstanceId, elementId, extraParams);
+
+ return db.deleteRecords(this.DRAFT_TABLE, params);
+ } catch (error) {
+ // Ignore errors, probably no draft stored.
+ }
+ }
+
+ /**
+ * Return an object with the draft primary data converted to the right format.
+ *
+ * @param contextLevel Context level.
+ * @param contextInstanceId The instance ID related to the context.
+ * @param elementId Element ID.
+ * @param extraParams Object with extra params to identify the draft.
+ * @return Object with the fixed primary data.
+ */
+ protected fixDraftPrimaryData(contextLevel: string, contextInstanceId: number, elementId: string,
+ extraParams: {[name: string]: any}): CoreEditorDraftPrimaryData {
+
+ return {
+ contextlevel: contextLevel,
+ contextinstanceid: contextInstanceId,
+ elementid: elementId,
+ extraparams: this.utils.sortAndStringify(extraParams || {}),
+ };
+ }
+
+ /**
+ * Get a draft from DB.
+ *
+ * @param contextLevel Context level.
+ * @param contextInstanceId The instance ID related to the context.
+ * @param elementId Element ID.
+ * @param extraParams Object with extra params to identify the draft.
+ * @param siteId Site ID. If not defined, current site.
+ * @return Promise resolved with the draft data. Undefined if no draft stored.
+ */
+ async getDraft(contextLevel: string, contextInstanceId: number, elementId: string, extraParams: {[name: string]: any},
+ siteId?: string): Promise {
+
+ const db = await this.sitesProvider.getSiteDb(siteId);
+
+ const params = this.fixDraftPrimaryData(contextLevel, contextInstanceId, elementId, extraParams);
+
+ return db.getRecord(this.DRAFT_TABLE, params);
+ }
+
+ /**
+ * Get draft to resume it.
+ *
+ * @param contextLevel Context level.
+ * @param contextInstanceId The instance ID related to the context.
+ * @param elementId Element ID.
+ * @param extraParams Object with extra params to identify the draft.
+ * @param pageInstance Unique identifier to prevent storing data from several sources at the same time.
+ * @param siteId Site ID. If not defined, current site.
+ * @return Promise resolved with the draft text. Undefined if no draft stored.
+ */
+ async resumeDraft(contextLevel: string, contextInstanceId: number, elementId: string, extraParams: {[name: string]: any},
+ pageInstance: string, siteId?: string): Promise {
+
+ try {
+ // Check if there is a draft stored.
+ const entry = await this.getDraft(contextLevel, contextInstanceId, elementId, extraParams, siteId);
+
+ // There is a draft stored. Update its page instance.
+ try {
+ const db = await this.sitesProvider.getSiteDb(siteId);
+
+ entry.pageinstance = pageInstance;
+ entry.timemodified = Date.now();
+
+ await db.insertRecord(this.DRAFT_TABLE, entry);
+ } catch (error) {
+ // Ignore errors saving the draft. It shouldn't happen.
+ }
+
+ return entry.drafttext;
+ } catch (error) {
+ // No draft stored. Store an empty draft to save the pageinstance.
+ await this.saveDraft(contextLevel, contextInstanceId, elementId, extraParams, pageInstance, '', siteId);
+ }
+ }
+
+ /**
+ * Save a draft in DB.
+ *
+ * @param contextLevel Context level.
+ * @param contextInstanceId The instance ID related to the context.
+ * @param elementId Element ID.
+ * @param extraParams Object with extra params to identify the draft.
+ * @param pageInstance Unique identifier to prevent storing data from several sources at the same time.
+ * @param draftText The text to store.
+ * @param siteId Site ID. If not defined, current site.
+ * @return Promise resolved when done.
+ */
+ async saveDraft(contextLevel: string, contextInstanceId: number, elementId: string, extraParams: {[name: string]: any},
+ pageInstance: string, draftText: string, siteId?: string): Promise {
+
+ let timecreated = Date.now();
+ let entry: CoreEditorDraft;
+
+ // Check if there is a draft already stored.
+ try {
+ entry = await this.getDraft(contextLevel, contextInstanceId, elementId, extraParams, siteId);
+
+ timecreated = entry.timecreated;
+ } catch (error) {
+ // No draft already stored.
+ }
+
+ if (entry && entry.pageinstance != pageInstance) {
+ this.logger.warning(`Discarding draft because of pageinstance. Context '${contextLevel}' '${contextInstanceId}', ` +
+ `element '${elementId}'`);
+ throw null;
+ }
+
+ const db = await this.sitesProvider.getSiteDb(siteId);
+
+ const data: CoreEditorDraft = this.fixDraftPrimaryData(contextLevel, contextInstanceId, elementId, extraParams);
+
+ data.drafttext = (draftText || '').trim();
+ data.pageinstance = pageInstance;
+ data.timecreated = timecreated;
+ data.timemodified = Date.now();
+
+ await db.insertRecord(this.DRAFT_TABLE, data);
+ }
+}
+
+/**
+ * Primary data to identify a stored draft.
+ */
+type CoreEditorDraftPrimaryData = {
+ contextlevel: string; // Context level.
+ contextinstanceid: number; // The instance ID related to the context.
+ elementid: string; // Element ID.
+ extraparams: string; // Extra params stringified.
+};
+
+/**
+ * Draft data stored.
+ */
+type CoreEditorDraft = CoreEditorDraftPrimaryData & {
+ drafttext?: string; // Draft text stored.
+ pageinstance?: string; // Unique identifier to prevent storing data from several sources at the same time.
+ timecreated?: number; // Time created.
+ timemodified?: number; // Time modified.
+};
From 5a79151b01f1999de6c1f927cbe00c1fa28d303a Mon Sep 17 00:00:00 2001
From: Dani Palou
Date: Fri, 31 Jan 2020 10:08:24 +0100
Subject: [PATCH 3/9] MOBILE-3323 editor: Save and restore drafts
---
scripts/langindex.json | 2 +
.../calendar/pages/edit-event/edit-event.html | 2 +-
.../addon-mod-assign-feedback-comments.html | 3 +-
...ddon-mod-assign-submission-onlinetext.html | 2 +-
.../onlinetext/component/onlinetext.ts | 14 +-
.../addon-mod-data-field-textarea.html | 2 +-
.../fields/textarea/component/textarea.ts | 6 +-
.../components/post/addon-mod-forum-post.html | 2 +-
.../edit-post/addon-mod-forum-edit-post.html | 2 +-
.../pages/new-discussion/new-discussion.html | 2 +-
src/addon/mod/glossary/pages/edit/edit.html | 2 +-
src/addon/mod/glossary/pages/edit/edit.ts | 5 +
src/addon/mod/lesson/pages/player/player.html | 2 +-
src/addon/mod/wiki/pages/edit/edit.html | 2 +-
src/addon/mod/wiki/pages/edit/edit.ts | 15 ++
...ddon-mod-workshop-assessment-strategy.html | 2 +-
.../workshop/pages/assessment/assessment.html | 2 +-
.../edit-submission/edit-submission.html | 2 +-
.../pages/edit-submission/edit-submission.ts | 5 +
.../workshop/pages/submission/submission.html | 2 +-
.../essay/component/addon-qtype-essay.html | 2 +-
.../addon-user-profile-field-textarea.html | 2 +-
src/assets/lang/en.json | 2 +
.../core-editor-rich-text-editor.html | 13 +-
.../rich-text-editor/rich-text-editor.scss | 18 ++-
.../rich-text-editor/rich-text-editor.ts | 144 +++++++++++++++++-
src/core/editor/lang/en.json | 4 +
src/theme/variables.scss | 5 -
28 files changed, 229 insertions(+), 37 deletions(-)
create mode 100644 src/core/editor/lang/en.json
diff --git a/scripts/langindex.json b/scripts/langindex.json
index 344e7460d4e..339c56c5afb 100644
--- a/scripts/langindex.json
+++ b/scripts/langindex.json
@@ -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",
diff --git a/src/addon/calendar/pages/edit-event/edit-event.html b/src/addon/calendar/pages/edit-event/edit-event.html
index 9eae210f8d8..55a2cd5846f 100644
--- a/src/addon/calendar/pages/edit-event/edit-event.html
+++ b/src/addon/calendar/pages/edit-event/edit-event.html
@@ -86,7 +86,7 @@
{{ 'core.description' | translate }}
-
+
diff --git a/src/addon/mod/assign/feedback/comments/component/addon-mod-assign-feedback-comments.html b/src/addon/mod/assign/feedback/comments/component/addon-mod-assign-feedback-comments.html
index 6a2fff370f0..75892386b1a 100644
--- a/src/addon/mod/assign/feedback/comments/component/addon-mod-assign-feedback-comments.html
+++ b/src/addon/mod/assign/feedback/comments/component/addon-mod-assign-feedback-comments.html
@@ -19,5 +19,6 @@ {{ plugin.name }}
-
+
+
diff --git a/src/addon/mod/assign/submission/onlinetext/component/addon-mod-assign-submission-onlinetext.html b/src/addon/mod/assign/submission/onlinetext/component/addon-mod-assign-submission-onlinetext.html
index a629ab32509..a659af7a9a9 100644
--- a/src/addon/mod/assign/submission/onlinetext/component/addon-mod-assign-submission-onlinetext.html
+++ b/src/addon/mod/assign/submission/onlinetext/component/addon-mod-assign-submission-onlinetext.html
@@ -15,6 +15,6 @@ {{ 'addon.mod_assign.wordlimit' | translate }}
{{ 'core.numwords' | translate: {'$a': words + ' / ' + configs.wordlimit} }}
-
+
diff --git a/src/addon/mod/assign/submission/onlinetext/component/onlinetext.ts b/src/addon/mod/assign/submission/onlinetext/component/onlinetext.ts
index 70ee9d183ce..a788de6674f 100644
--- a/src/addon/mod/assign/submission/onlinetext/component/onlinetext.ts
+++ b/src/addon/mod/assign/submission/onlinetext/component/onlinetext.ts
@@ -14,6 +14,7 @@
import { Component, OnInit, ElementRef } from '@angular/core';
import { FormBuilder, FormControl } from '@angular/forms';
+import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { AddonModAssignProvider } from '../../../providers/assign';
@@ -35,16 +36,23 @@ export class AddonModAssignSubmissionOnlineTextComponent extends AddonModAssignS
text: string;
loaded: boolean;
wordLimitEnabled: boolean;
+ currentUserId: number;
protected wordCountTimeout: any;
protected element: HTMLElement;
- constructor(protected fb: FormBuilder, protected domUtils: CoreDomUtilsProvider, protected textUtils: CoreTextUtilsProvider,
- protected assignProvider: AddonModAssignProvider, protected assignOfflineProvider: AddonModAssignOfflineProvider,
- element: ElementRef) {
+ constructor(
+ protected fb: FormBuilder,
+ protected domUtils: CoreDomUtilsProvider,
+ protected textUtils: CoreTextUtilsProvider,
+ protected assignProvider: AddonModAssignProvider,
+ protected assignOfflineProvider: AddonModAssignOfflineProvider,
+ element: ElementRef,
+ sitesProvider: CoreSitesProvider) {
super();
this.element = element.nativeElement;
+ this.currentUserId = sitesProvider.getCurrentSiteUserId();
}
/**
diff --git a/src/addon/mod/data/fields/textarea/component/addon-mod-data-field-textarea.html b/src/addon/mod/data/fields/textarea/component/addon-mod-data-field-textarea.html
index 02ce6f3670d..680b92f898c 100644
--- a/src/addon/mod/data/fields/textarea/component/addon-mod-data-field-textarea.html
+++ b/src/addon/mod/data/fields/textarea/component/addon-mod-data-field-textarea.html
@@ -2,7 +2,7 @@
-
+
diff --git a/src/addon/mod/data/fields/textarea/component/textarea.ts b/src/addon/mod/data/fields/textarea/component/textarea.ts
index ba54212d783..d0d03359a00 100644
--- a/src/addon/mod/data/fields/textarea/component/textarea.ts
+++ b/src/addon/mod/data/fields/textarea/component/textarea.ts
@@ -49,10 +49,10 @@ export class AddonModDataFieldTextareaComponent extends AddonModDataFieldPluginC
* Initialize field.
*/
protected init(): void {
- if (this.isShowOrListMode()) {
- this.component = AddonModDataProvider.COMPONENT;
- this.componentId = this.database.coursemodule;
+ this.component = AddonModDataProvider.COMPONENT;
+ this.componentId = this.database.coursemodule;
+ if (this.isShowOrListMode()) {
return;
}
diff --git a/src/addon/mod/forum/components/post/addon-mod-forum-post.html b/src/addon/mod/forum/components/post/addon-mod-forum-post.html
index 02a3bbe42bf..cafe72514cd 100644
--- a/src/addon/mod/forum/components/post/addon-mod-forum-post.html
+++ b/src/addon/mod/forum/components/post/addon-mod-forum-post.html
@@ -64,7 +64,7 @@ {{post.userfullname}}
{{ 'addon.mod_forum.message' | translate }}
-
+
{{ 'addon.mod_forum.privatereply' | translate }}
diff --git a/src/addon/mod/forum/pages/edit-post/addon-mod-forum-edit-post.html b/src/addon/mod/forum/pages/edit-post/addon-mod-forum-edit-post.html
index 0a934fa27ac..3fd8d6e4af1 100644
--- a/src/addon/mod/forum/pages/edit-post/addon-mod-forum-edit-post.html
+++ b/src/addon/mod/forum/pages/edit-post/addon-mod-forum-edit-post.html
@@ -16,7 +16,7 @@
{{ 'addon.mod_forum.message' | translate }}
-
+
diff --git a/src/addon/mod/forum/pages/new-discussion/new-discussion.html b/src/addon/mod/forum/pages/new-discussion/new-discussion.html
index 95bb6e5cecb..6cfeb39f8b9 100644
--- a/src/addon/mod/forum/pages/new-discussion/new-discussion.html
+++ b/src/addon/mod/forum/pages/new-discussion/new-discussion.html
@@ -19,7 +19,7 @@
{{ 'addon.mod_forum.message' | translate }}
-
+
diff --git a/src/addon/mod/glossary/pages/edit/edit.html b/src/addon/mod/glossary/pages/edit/edit.html
index 3c3bfa0d72c..0bf02b4587c 100644
--- a/src/addon/mod/glossary/pages/edit/edit.html
+++ b/src/addon/mod/glossary/pages/edit/edit.html
@@ -15,7 +15,7 @@
{{ 'addon.mod_glossary.definition' | translate }}
-
+
0">
{{ 'addon.mod_glossary.categories' | translate }}
diff --git a/src/addon/mod/glossary/pages/edit/edit.ts b/src/addon/mod/glossary/pages/edit/edit.ts
index 7bb9e60eb4d..9cf8b43553c 100644
--- a/src/addon/mod/glossary/pages/edit/edit.ts
+++ b/src/addon/mod/glossary/pages/edit/edit.ts
@@ -51,6 +51,7 @@ export class AddonModGlossaryEditPage implements OnInit {
attachments = [];
definitionControl = new FormControl();
categories = [];
+ editorExtraParams: {[name: string]: any} = {};
protected courseId: number;
protected module: any;
@@ -113,6 +114,10 @@ export class AddonModGlossaryEditPage implements OnInit {
this.originalData.files = files.slice();
});
}
+
+ if (entry.id) {
+ this.editorExtraParams.id = entry.id;
+ }
}
this.definitionControl.setValue(this.entry.definition);
diff --git a/src/addon/mod/lesson/pages/player/player.html b/src/addon/mod/lesson/pages/player/player.html
index 13c7e7f0b65..b8526c401f1 100644
--- a/src/addon/mod/lesson/pages/player/player.html
+++ b/src/addon/mod/lesson/pages/player/player.html
@@ -57,7 +57,7 @@
-
+
{{ 'addon.mod_lesson.youranswer' | translate }}
diff --git a/src/addon/mod/wiki/pages/edit/edit.html b/src/addon/mod/wiki/pages/edit/edit.html
index c9f61f896d8..2381df6c35d 100644
--- a/src/addon/mod/wiki/pages/edit/edit.html
+++ b/src/addon/mod/wiki/pages/edit/edit.html
@@ -17,7 +17,7 @@
-
+
diff --git a/src/addon/mod/wiki/pages/edit/edit.ts b/src/addon/mod/wiki/pages/edit/edit.ts
index 160bfeeb2da..033ec982e0a 100644
--- a/src/addon/mod/wiki/pages/edit/edit.ts
+++ b/src/addon/mod/wiki/pages/edit/edit.ts
@@ -45,6 +45,7 @@ export class AddonModWikiEditPage implements OnInit, OnDestroy {
component = AddonModWikiProvider.COMPONENT; // Component to link the files to.
componentId: number; // Component ID to link the files to.
wrongVersionLock: boolean; // Whether the page lock doesn't match the initial one.
+ editorExtraParams: {[name: string]: any} = {};
protected module: any; // Wiki module instance.
protected courseId: number; // Course the wiki belongs to.
@@ -101,6 +102,20 @@ export class AddonModWikiEditPage implements OnInit, OnDestroy {
// Block the wiki so it cannot be synced.
this.syncProvider.blockOperation(this.component, this.blockId);
+
+ if (!this.module.id) {
+ this.editorExtraParams.type = 'wiki';
+ }
+
+ if (this.pageId) {
+ this.editorExtraParams.pageid = this.pageId;
+
+ if (this.section) {
+ this.editorExtraParams.section = this.section;
+ }
+ } else if (pageTitle) {
+ this.editorExtraParams.pagetitle = pageTitle;
+ }
}
/**
diff --git a/src/addon/mod/workshop/components/assessment-strategy/addon-mod-workshop-assessment-strategy.html b/src/addon/mod/workshop/components/assessment-strategy/addon-mod-workshop-assessment-strategy.html
index 7f3b2bba75a..b79857e1d31 100644
--- a/src/addon/mod/workshop/components/assessment-strategy/addon-mod-workshop-assessment-strategy.html
+++ b/src/addon/mod/workshop/components/assessment-strategy/addon-mod-workshop-assessment-strategy.html
@@ -16,7 +16,7 @@ {{ 'addon.mod_workshop.overallfeedback' | translate }}
{{ 'addon.mod_workshop.feedbackauthor' | translate }}
-
+
{{ 'addon.mod_workshop.gradinggradecalculated' | translate }}
{{ 'addon.mod_workshop.feedbackreviewer' | translate }}
-
+
diff --git a/src/addon/mod/workshop/pages/edit-submission/edit-submission.html b/src/addon/mod/workshop/pages/edit-submission/edit-submission.html
index 71b1e535d08..a7f3bad68ac 100644
--- a/src/addon/mod/workshop/pages/edit-submission/edit-submission.html
+++ b/src/addon/mod/workshop/pages/edit-submission/edit-submission.html
@@ -18,7 +18,7 @@
{{ 'addon.mod_workshop.submissioncontent' | translate }}
-
+
diff --git a/src/addon/mod/workshop/pages/edit-submission/edit-submission.ts b/src/addon/mod/workshop/pages/edit-submission/edit-submission.ts
index 816a29b46bb..c3fb1edbb6f 100644
--- a/src/addon/mod/workshop/pages/edit-submission/edit-submission.ts
+++ b/src/addon/mod/workshop/pages/edit-submission/edit-submission.ts
@@ -51,6 +51,7 @@ export class AddonModWorkshopEditSubmissionPage implements OnInit, OnDestroy {
component = AddonModWorkshopProvider.COMPONENT;
componentId: number;
editForm: FormGroup; // The form group.
+ editorExtraParams: {[name: string]: any} = {};
protected workshopId: number;
protected submissionId: number;
@@ -86,6 +87,10 @@ export class AddonModWorkshopEditSubmissionPage implements OnInit, OnDestroy {
this.editForm = new FormGroup({});
this.editForm.addControl('title', this.fb.control('', Validators.required));
this.editForm.addControl('content', this.fb.control(''));
+
+ if (this.submissionId) {
+ this.editorExtraParams.id = this.submissionId;
+ }
}
/**
diff --git a/src/addon/mod/workshop/pages/submission/submission.html b/src/addon/mod/workshop/pages/submission/submission.html
index 41fbecd1d9b..0951709aecf 100644
--- a/src/addon/mod/workshop/pages/submission/submission.html
+++ b/src/addon/mod/workshop/pages/submission/submission.html
@@ -87,7 +87,7 @@ {{ 'addon.mod_workshop.gradecalculated' | translate }}
{{ 'addon.mod_workshop.feedbackauthor' | translate }}
-
+
diff --git a/src/addon/qtype/essay/component/addon-qtype-essay.html b/src/addon/qtype/essay/component/addon-qtype-essay.html
index 5c171fedc65..13462423bc3 100644
--- a/src/addon/qtype/essay/component/addon-qtype-essay.html
+++ b/src/addon/qtype/essay/component/addon-qtype-essay.html
@@ -11,7 +11,7 @@
-
+
diff --git a/src/addon/userprofilefield/textarea/component/addon-user-profile-field-textarea.html b/src/addon/userprofilefield/textarea/component/addon-user-profile-field-textarea.html
index 1d149a8ed4a..8908db521b2 100644
--- a/src/addon/userprofilefield/textarea/component/addon-user-profile-field-textarea.html
+++ b/src/addon/userprofilefield/textarea/component/addon-user-profile-field-textarea.html
@@ -9,5 +9,5 @@ {{ field.name }}
{{ field.name }}
-
+
\ No newline at end of file
diff --git a/src/assets/lang/en.json b/src/assets/lang/en.json
index e9673f525f8..d3f4ff056a5 100644
--- a/src/assets/lang/en.json
+++ b/src/assets/lang/en.json
@@ -1482,6 +1482,8 @@
"core.downloaded": "Downloaded",
"core.downloading": "Downloading",
"core.edit": "Edit",
+ "core.editor.autosavesucceeded": "Draft saved.",
+ "core.editor.textrecovered": "A draft version of this text was automatically restored.",
"core.emptysplit": "This page will appear blank if the left panel is empty or is loading.",
"core.error": "Error",
"core.errorchangecompletion": "An error occurred while changing the completion status. Please try again.",
diff --git a/src/core/editor/components/rich-text-editor/core-editor-rich-text-editor.html b/src/core/editor/components/rich-text-editor/core-editor-rich-text-editor.html
index ba2bd897f53..6b3a503edcb 100644
--- a/src/core/editor/components/rich-text-editor/core-editor-rich-text-editor.html
+++ b/src/core/editor/components/rich-text-editor/core-editor-rich-text-editor.html
@@ -1,7 +1,14 @@
-
-
+
+
+
+
+
-
+
+
+ {{ infoMessage | translate }}
+
+
-
+
diff --git a/src/addon/mod/data/pages/search/search.ts b/src/addon/mod/data/pages/search/search.ts
index 5aff12b6bf9..5834e6cccda 100644
--- a/src/addon/mod/data/pages/search/search.ts
+++ b/src/addon/mod/data/pages/search/search.ts
@@ -12,9 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import { Component } from '@angular/core';
+import { Component, ViewChild, ElementRef } from '@angular/core';
import { IonicPage, NavParams, ViewController } from 'ionic-angular';
import { FormBuilder, FormGroup } from '@angular/forms';
+import { CoreEventsProvider } from '@providers/events';
+import { CoreSitesProvider } from '@providers/sites';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreTextUtilsProvider } from '@providers/utils/text';
@@ -32,6 +34,8 @@ import { CoreTagProvider } from '@core/tag/providers/tag';
templateUrl: 'search.html',
})
export class AddonModDataSearchPage {
+ @ViewChild('searchFormEl') formElement: ElementRef;
+
search: any;
fields: any;
data: any;
@@ -41,10 +45,17 @@ export class AddonModDataSearchPage {
jsData: any;
fieldsArray: any;
- constructor(params: NavParams, private viewCtrl: ViewController, fb: FormBuilder, protected utils: CoreUtilsProvider,
- protected domUtils: CoreDomUtilsProvider, protected fieldsDelegate: AddonModDataFieldsDelegate,
- protected textUtils: CoreTextUtilsProvider, protected dataHelper: AddonModDataHelperProvider,
- private tagProvider: CoreTagProvider) {
+ constructor(params: NavParams,
+ protected viewCtrl: ViewController,
+ fb: FormBuilder,
+ protected utils: CoreUtilsProvider,
+ protected domUtils: CoreDomUtilsProvider,
+ protected fieldsDelegate: AddonModDataFieldsDelegate,
+ protected textUtils: CoreTextUtilsProvider,
+ protected dataHelper: AddonModDataHelperProvider,
+ protected tagProvider: CoreTagProvider,
+ protected eventsProvider: CoreEventsProvider,
+ protected sitesProvider: CoreSitesProvider) {
this.search = params.get('search');
this.fields = params.get('fields');
this.data = params.get('data');
@@ -209,6 +220,11 @@ export class AddonModDataSearchPage {
this.search.sortBy = searchedData.sortBy;
this.search.sortDirection = searchedData.sortDirection;
+ this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
+ form: this.formElement.nativeElement,
+ online: false,
+ }, this.sitesProvider.getCurrentSiteId());
+
this.closeModal(this.search);
}
}
diff --git a/src/addon/mod/data/providers/data.ts b/src/addon/mod/data/providers/data.ts
index 0e70b084c4f..481896b2850 100644
--- a/src/addon/mod/data/providers/data.ts
+++ b/src/addon/mod/data/providers/data.ts
@@ -126,7 +126,8 @@ export class AddonModDataProvider {
.then((entry) => {
return {
// Return provissional entry Id.
- newentryid: entry
+ newentryid: entry,
+ sent: false,
};
});
};
@@ -142,7 +143,11 @@ export class AddonModDataProvider {
return storeOffline();
}
- return this.addEntryOnline(dataId, contents, groupId, siteId).catch((error) => {
+ return this.addEntryOnline(dataId, contents, groupId, siteId).then((result) => {
+ result.sent = true;
+
+ return result;
+ }).catch((error) => {
if (this.utils.isWebServiceError(error)) {
// The WebService has thrown an error, this means that responses cannot be submitted.
return Promise.reject(error);
@@ -194,7 +199,12 @@ export class AddonModDataProvider {
const storeOffline = (): Promise => {
const action = approve ? 'approve' : 'disapprove';
- return this.dataOffline.saveEntry(dataId, entryId, action, courseId, undefined, undefined, undefined, siteId);
+ return this.dataOffline.saveEntry(dataId, entryId, action, courseId, undefined, undefined, undefined, siteId)
+ .then(() => {
+ return {
+ sent: false,
+ };
+ });
};
// Get if the opposite action is not synced.
@@ -210,7 +220,11 @@ export class AddonModDataProvider {
return storeOffline();
}
- return this.approveEntryOnline(entryId, approve, siteId).catch((error) => {
+ return this.approveEntryOnline(entryId, approve, siteId).then(() => {
+ return {
+ sent: true,
+ };
+ }).catch((error) => {
if (this.utils.isWebServiceError(error)) {
// The WebService has thrown an error, this means that responses cannot be submitted.
return Promise.reject(error);
@@ -288,7 +302,12 @@ export class AddonModDataProvider {
// Convenience function to store a data to be synchronized later.
const storeOffline = (): Promise => {
- return this.dataOffline.saveEntry(dataId, entryId, 'delete', courseId, undefined, undefined, undefined, siteId);
+ return this.dataOffline.saveEntry(dataId, entryId, 'delete', courseId, undefined, undefined, undefined, siteId)
+ .then(() => {
+ return {
+ sent: false,
+ };
+ });
};
let justAdded = false;
@@ -318,7 +337,11 @@ export class AddonModDataProvider {
return storeOffline();
}
- return this.deleteEntryOnline(entryId, siteId).catch((error) => {
+ return this.deleteEntryOnline(entryId, siteId).then(() => {
+ return {
+ sent: true,
+ };
+ }).catch((error) => {
if (this.utils.isWebServiceError(error)) {
// The WebService has thrown an error, this means that responses cannot be submitted.
return Promise.reject(error);
@@ -368,7 +391,8 @@ export class AddonModDataProvider {
return this.dataOffline.saveEntry(dataId, entryId, 'edit', courseId, undefined, contents, undefined, siteId)
.then(() => {
return {
- updated: true
+ updated: true,
+ sent: false,
};
});
};
@@ -408,6 +432,7 @@ export class AddonModDataProvider {
return this.addEntry(dataId, entryId, courseId, contents, groupId, fields, siteId, forceOffline)
.then((result) => {
result.updated = true;
+ result.sent = true;
return result;
});
@@ -418,7 +443,11 @@ export class AddonModDataProvider {
return storeOffline();
}
- return this.editEntryOnline(entryId, contents, siteId).catch((error) => {
+ return this.editEntryOnline(entryId, contents, siteId).then((result) => {
+ result.sent = true;
+
+ return result;
+ }).catch((error) => {
if (this.utils.isWebServiceError(error)) {
// The WebService has thrown an error, this means that responses cannot be submitted.
return Promise.reject(error);
diff --git a/src/addon/mod/lesson/components/index/addon-mod-lesson-index.html b/src/addon/mod/lesson/components/index/addon-mod-lesson-index.html
index 440d7f3831c..f7ac672e0f9 100644
--- a/src/addon/mod/lesson/components/index/addon-mod-lesson-index.html
+++ b/src/addon/mod/lesson/components/index/addon-mod-lesson-index.html
@@ -34,7 +34,7 @@
-
+
{{ 'addon.mod_lesson.enterpassword' | translate }}
diff --git a/src/addon/mod/lesson/components/index/index.ts b/src/addon/mod/lesson/components/index/index.ts
index 17dec12eee2..b3b4b95a7cc 100644
--- a/src/addon/mod/lesson/components/index/index.ts
+++ b/src/addon/mod/lesson/components/index/index.ts
@@ -12,8 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import { Component, Optional, Injector, Input, ViewChild } from '@angular/core';
+import { Component, Optional, Injector, Input, ViewChild, ElementRef } from '@angular/core';
import { Content, NavController } from 'ionic-angular';
+import { CoreEventsProvider } from '@providers/events';
import { CoreGroupsProvider, CoreGroupInfo } from '@providers/groups';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreUtilsProvider } from '@providers/utils/utils';
@@ -35,6 +36,7 @@ import { CoreTabsComponent } from '@components/tabs/tabs';
})
export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityComponent {
@ViewChild(CoreTabsComponent) tabsComponent: CoreTabsComponent;
+ @ViewChild('passwordForm') formElement: ElementRef;
@Input() group: number; // The group to display.
@Input() action: string; // The "action" to display first.
@@ -584,6 +586,11 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo
this.loaded = true;
this.refreshIcon = 'refresh';
this.syncIcon = 'sync';
+
+ this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
+ form: this.formElement.nativeElement,
+ online: true,
+ }, this.siteId);
});
}
diff --git a/src/addon/mod/lesson/pages/password-modal/password-modal.html b/src/addon/mod/lesson/pages/password-modal/password-modal.html
index b673d540c73..3c35a3dccc7 100644
--- a/src/addon/mod/lesson/pages/password-modal/password-modal.html
+++ b/src/addon/mod/lesson/pages/password-modal/password-modal.html
@@ -9,7 +9,7 @@
-
+
{{ 'addon.mod_lesson.enterpassword' | translate }}
diff --git a/src/addon/mod/lesson/pages/password-modal/password-modal.ts b/src/addon/mod/lesson/pages/password-modal/password-modal.ts
index 13fbfcdb1a9..d72df1ca4d9 100644
--- a/src/addon/mod/lesson/pages/password-modal/password-modal.ts
+++ b/src/addon/mod/lesson/pages/password-modal/password-modal.ts
@@ -12,8 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import { Component } from '@angular/core';
+import { Component, ViewChild, ElementRef } from '@angular/core';
import { IonicPage, ViewController } from 'ionic-angular';
+import { CoreEventsProvider } from '@providers/events';
+import { CoreSitesProvider } from '@providers/sites';
/**
* Modal that asks the password for a lesson.
@@ -24,8 +26,11 @@ import { IonicPage, ViewController } from 'ionic-angular';
templateUrl: 'password-modal.html',
})
export class AddonModLessonPasswordModalPage {
+ @ViewChild('passwordForm') formElement: ElementRef;
- constructor(protected viewCtrl: ViewController) { }
+ constructor(protected viewCtrl: ViewController,
+ protected eventsProvider: CoreEventsProvider,
+ protected sitesProvider: CoreSitesProvider) { }
/**
* Send the password back.
@@ -37,6 +42,11 @@ export class AddonModLessonPasswordModalPage {
e.preventDefault();
e.stopPropagation();
+ this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
+ form: this.formElement.nativeElement,
+ online: false,
+ }, this.sitesProvider.getCurrentSiteId());
+
this.viewCtrl.dismiss(password.value);
}
diff --git a/src/addon/mod/lesson/pages/player/player.html b/src/addon/mod/lesson/pages/player/player.html
index b8526c401f1..dfe4c3e864d 100644
--- a/src/addon/mod/lesson/pages/player/player.html
+++ b/src/addon/mod/lesson/pages/player/player.html
@@ -38,7 +38,7 @@
-
+
diff --git a/src/addon/mod/lesson/pages/player/player.ts b/src/addon/mod/lesson/pages/player/player.ts
index c29ad99b526..7ab23e96f29 100644
--- a/src/addon/mod/lesson/pages/player/player.ts
+++ b/src/addon/mod/lesson/pages/player/player.ts
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import { Component, OnInit, OnDestroy, ViewChild, ChangeDetectorRef } from '@angular/core';
+import { Component, OnInit, OnDestroy, ViewChild, ChangeDetectorRef, ElementRef } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { IonicPage, NavParams, Content, PopoverController, ModalController, Modal, NavController } from 'ionic-angular';
import { TranslateService } from '@ngx-translate/core';
@@ -41,6 +41,7 @@ import { AddonModLessonHelperProvider } from '../../providers/helper';
})
export class AddonModLessonPlayerPage implements OnInit, OnDestroy {
@ViewChild(Content) content: Content;
+ @ViewChild('questionFormEl') formElement: ElementRef;
component = AddonModLessonProvider.COMPONENT;
LESSON_EOL = AddonModLessonProvider.LESSON_EOL;
@@ -540,15 +541,23 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy {
* Process a page, sending some data.
*
* @param data The data to send.
+ * @param formSubmitted Whether a form was submitted.
* @return Promise resolved when done.
*/
- protected processPage(data: any): Promise {
+ protected processPage(data: any, formSubmitted?: boolean): Promise {
this.loaded = false;
const args = [this.lesson, this.courseId, this.pageData, data, this.password, this.review, this.offline, this.accessInfo,
this.jumps];
return this.callFunction(this.lessonProvider.processPage.bind(this.lessonProvider), args, 6, 8).then((result) => {
+ if (formSubmitted) {
+ this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
+ form: this.formElement.nativeElement,
+ online: result.sent,
+ }, this.sitesProvider.getCurrentSiteId());
+ }
+
if (!this.offline && !this.review && this.lessonProvider.isLessonOffline(this.lesson)) {
// Lesson allows offline and the user changed some data in server. Update cached data.
const retake = this.accessInfo.attemptscount;
@@ -637,7 +646,7 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy {
// Use getRawValue to include disabled values.
const data = this.lessonHelper.prepareQuestionData(this.question, this.questionForm.getRawValue());
- this.processPage(data).finally(() => {
+ this.processPage(data, true).finally(() => {
this.loaded = true;
});
}
diff --git a/src/addon/mod/lesson/providers/lesson.ts b/src/addon/mod/lesson/providers/lesson.ts
index b7fabe1f13f..a4db30c6f7f 100644
--- a/src/addon/mod/lesson/providers/lesson.ts
+++ b/src/addon/mod/lesson/providers/lesson.ts
@@ -3089,6 +3089,7 @@ export class AddonModLessonProvider {
result.warnings = [];
result.displaymenu = pageData.displaymenu; // Keep the same value since we can't calculate it in offline.
result.messages = this.getPageProcessMessages(lesson, accessInfo, result, review, jumps);
+ result.sent = false;
Object.assign(result, calculatedData);
return result;
@@ -3104,6 +3105,8 @@ export class AddonModLessonProvider {
review: review
}, this.sitesProvider.getCurrentSiteId());
+ response.sent = true;
+
return response;
});
}
diff --git a/src/addon/mod/quiz/pages/player/player.html b/src/addon/mod/quiz/pages/player/player.html
index e632829c1e5..81d271d7de7 100644
--- a/src/addon/mod/quiz/pages/player/player.html
+++ b/src/addon/mod/quiz/pages/player/player.html
@@ -45,7 +45,7 @@
-
+
diff --git a/src/addon/mod/quiz/pages/player/player.ts b/src/addon/mod/quiz/pages/player/player.ts
index 81f7989d534..31acddaa46c 100644
--- a/src/addon/mod/quiz/pages/player/player.ts
+++ b/src/addon/mod/quiz/pages/player/player.ts
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import { Component, OnInit, OnDestroy, ViewChild, ChangeDetectorRef, ViewChildren, QueryList } from '@angular/core';
+import { Component, OnInit, OnDestroy, ViewChild, ChangeDetectorRef, ViewChildren, QueryList, ElementRef } from '@angular/core';
import { IonicPage, NavParams, Content, PopoverController, ModalController, Modal, NavController } from 'ionic-angular';
import { TranslateService } from '@ngx-translate/core';
import { CoreEventsProvider } from '@providers/events';
@@ -41,6 +41,7 @@ import { Subscription } from 'rxjs';
export class AddonModQuizPlayerPage implements OnInit, OnDestroy {
@ViewChild(Content) content: Content;
@ViewChildren(CoreQuestionComponent) questionComponents: QueryList;
+ @ViewChild('quizForm') formElement: ElementRef;
quiz: any; // The quiz the attempt belongs to.
attempt: any; // The attempt being attempted.
@@ -585,6 +586,11 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy {
// Answers saved, cancel auto save.
this.autoSave.cancelAutoSave();
this.autoSave.hideAutoSaveError();
+
+ this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
+ form: this.formElement.nativeElement,
+ online: !this.offline,
+ }, this.sitesProvider.getCurrentSiteId());
});
}
diff --git a/src/addon/mod/quiz/pages/preflight-modal/preflight-modal.html b/src/addon/mod/quiz/pages/preflight-modal/preflight-modal.html
index c00c0827759..69d32d7abd2 100644
--- a/src/addon/mod/quiz/pages/preflight-modal/preflight-modal.html
+++ b/src/addon/mod/quiz/pages/preflight-modal/preflight-modal.html
@@ -10,7 +10,7 @@
-
+
diff --git a/src/addon/mod/quiz/pages/preflight-modal/preflight-modal.ts b/src/addon/mod/quiz/pages/preflight-modal/preflight-modal.ts
index 590d03137ce..28681c8a5ca 100644
--- a/src/addon/mod/quiz/pages/preflight-modal/preflight-modal.ts
+++ b/src/addon/mod/quiz/pages/preflight-modal/preflight-modal.ts
@@ -12,10 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import { Component, OnInit, Injector, ViewChild } from '@angular/core';
+import { Component, OnInit, Injector, ViewChild, ElementRef } from '@angular/core';
import { IonicPage, ViewController, NavParams, Content } from 'ionic-angular';
import { TranslateService } from '@ngx-translate/core';
import { FormBuilder, FormGroup } from '@angular/forms';
+import { CoreEventsProvider } from '@providers/events';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { AddonModQuizAccessRuleDelegate } from '../../providers/access-rules-delegate';
@@ -31,6 +32,7 @@ import { AddonModQuizAccessRuleDelegate } from '../../providers/access-rules-del
export class AddonModQuizPreflightModalPage implements OnInit {
@ViewChild(Content) content: Content;
+ @ViewChild('preflightFormEl') formElement: ElementRef;
preflightForm: FormGroup;
title: string;
@@ -43,9 +45,15 @@ export class AddonModQuizPreflightModalPage implements OnInit {
protected siteId: string;
protected rules: string[];
- constructor(params: NavParams, fb: FormBuilder, translate: TranslateService, sitesProvider: CoreSitesProvider,
- protected viewCtrl: ViewController, protected accessRuleDelegate: AddonModQuizAccessRuleDelegate,
- protected injector: Injector, protected domUtils: CoreDomUtilsProvider) {
+ constructor(params: NavParams,
+ fb: FormBuilder,
+ translate: TranslateService,
+ sitesProvider: CoreSitesProvider,
+ protected viewCtrl: ViewController,
+ protected accessRuleDelegate: AddonModQuizAccessRuleDelegate,
+ protected injector: Injector,
+ protected domUtils: CoreDomUtilsProvider,
+ protected eventsProvider: CoreEventsProvider) {
this.title = params.get('title') || translate.instant('addon.mod_quiz.startattempt');
this.quiz = params.get('quiz');
@@ -112,6 +120,11 @@ export class AddonModQuizPreflightModalPage implements OnInit {
this.domUtils.showErrorModal('core.errorinvalidform', true);
}
} else {
+ this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
+ form: this.formElement.nativeElement,
+ online: false,
+ }, this.siteId);
+
this.viewCtrl.dismiss(this.preflightForm.value);
}
}
diff --git a/src/addon/mod/wiki/pages/edit/edit.html b/src/addon/mod/wiki/pages/edit/edit.html
index 2381df6c35d..aa2491c90cc 100644
--- a/src/addon/mod/wiki/pages/edit/edit.html
+++ b/src/addon/mod/wiki/pages/edit/edit.html
@@ -11,7 +11,7 @@
-
+
diff --git a/src/addon/mod/wiki/pages/edit/edit.ts b/src/addon/mod/wiki/pages/edit/edit.ts
index 033ec982e0a..7df9ad26ae7 100644
--- a/src/addon/mod/wiki/pages/edit/edit.ts
+++ b/src/addon/mod/wiki/pages/edit/edit.ts
@@ -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 { FormControl, FormGroup, FormBuilder } from '@angular/forms';
import { TranslateService } from '@ngx-translate/core';
@@ -37,6 +37,8 @@ import { AddonModWikiSyncProvider, AddonModWikiSyncSubwikiResult } from '../../p
})
export class AddonModWikiEditPage implements OnInit, OnDestroy {
+ @ViewChild('editPageForm') formElement: ElementRef;
+
title: string; // Title to display.
pageForm: FormGroup; // The form group.
contentControl: FormControl; // The FormControl for the page content.
@@ -423,6 +425,12 @@ export class AddonModWikiEditPage implements OnInit, OnDestroy {
if (this.editing) {
// Edit existing page.
promise = this.wikiProvider.editPage(this.pageId, text, this.section).then(() => {
+
+ this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
+ form: this.formElement.nativeElement,
+ online: true,
+ }, this.sitesProvider.getCurrentSiteId());
+
// Invalidate page since it changed.
return this.wikiProvider.invalidatePage(this.pageId).then(() => {
return this.gotoPage(title);
@@ -456,6 +464,12 @@ export class AddonModWikiEditPage implements OnInit, OnDestroy {
let wikiId = this.wikiId || (this.module && this.module.instance);
return this.wikiProvider.newPage(title, text, this.subwikiId, wikiId, this.userId, this.groupId).then((id) => {
+
+ this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
+ form: this.formElement.nativeElement,
+ online: id > 0,
+ }, this.sitesProvider.getCurrentSiteId());
+
if (id > 0) {
// Page was created, get its data and go to the page.
this.pageId = id;
diff --git a/src/addon/mod/workshop/components/assessment-strategy/addon-mod-workshop-assessment-strategy.html b/src/addon/mod/workshop/components/assessment-strategy/addon-mod-workshop-assessment-strategy.html
index b79857e1d31..c3bb1fd413b 100644
--- a/src/addon/mod/workshop/components/assessment-strategy/addon-mod-workshop-assessment-strategy.html
+++ b/src/addon/mod/workshop/components/assessment-strategy/addon-mod-workshop-assessment-strategy.html
@@ -1,6 +1,6 @@
{{ 'addon.mod_workshop.assessmentform' | translate }}
-
+
diff --git a/src/addon/mod/workshop/components/assessment-strategy/assessment-strategy.ts b/src/addon/mod/workshop/components/assessment-strategy/assessment-strategy.ts
index e92c1e99875..9b239ddacbe 100644
--- a/src/addon/mod/workshop/components/assessment-strategy/assessment-strategy.ts
+++ b/src/addon/mod/workshop/components/assessment-strategy/assessment-strategy.ts
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import { Component, Input, OnInit, Injector } from '@angular/core';
+import { Component, Input, OnInit, Injector, ViewChild, ElementRef } from '@angular/core';
import { FormControl } from '@angular/forms';
import { TranslateService } from '@ngx-translate/core';
import { CoreSyncProvider } from '@providers/sync';
@@ -44,6 +44,8 @@ export class AddonModWorkshopAssessmentStrategyComponent implements OnInit {
@Input() strategy: string;
@Input() edit?: boolean;
+ @ViewChild('assessmentForm') formElement: ElementRef;
+
componentClass: any;
data = {
workshopId: 0,
@@ -292,7 +294,7 @@ export class AddonModWorkshopAssessmentStrategyComponent implements OnInit {
// Save assessment in offline.
return this.workshopOffline.saveAssessment(this.workshop.id, this.assessmentId, this.workshop.course,
assessmentData).then(() => {
- // Don't return anything.
+ return false;
});
}
@@ -301,6 +303,12 @@ export class AddonModWorkshopAssessmentStrategyComponent implements OnInit {
return this.workshopProvider.updateAssessment(this.workshop.id, this.assessmentId, this.workshop.course,
assessmentData, false, allowOffline);
}).then((grade) => {
+
+ this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
+ form: this.formElement.nativeElement,
+ online: !!grade,
+ }, this.sitesProvider.getCurrentSiteId());
+
const promises = [];
// If sent to the server, invalidate and clean.
diff --git a/src/addon/mod/workshop/pages/assessment/assessment.html b/src/addon/mod/workshop/pages/assessment/assessment.html
index 6d093a0c41f..cfb72fa0090 100644
--- a/src/addon/mod/workshop/pages/assessment/assessment.html
+++ b/src/addon/mod/workshop/pages/assessment/assessment.html
@@ -38,7 +38,7 @@ {{profile.fullname}}
-
+
{{ 'addon.mod_workshop.assessmentsettings' | translate }}
diff --git a/src/addon/mod/workshop/pages/assessment/assessment.ts b/src/addon/mod/workshop/pages/assessment/assessment.ts
index 1fe9fe5aa95..ae9a53d6225 100644
--- a/src/addon/mod/workshop/pages/assessment/assessment.ts
+++ b/src/addon/mod/workshop/pages/assessment/assessment.ts
@@ -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, NavParams, NavController } from 'ionic-angular';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { TranslateService } from '@ngx-translate/core';
@@ -39,6 +39,8 @@ import { AddonModWorkshopSyncProvider } from '../../providers/sync';
})
export class AddonModWorkshopAssessmentPage implements OnInit, OnDestroy {
+ @ViewChild('evaluateFormEl') formElement: ElementRef;
+
assessment: any;
submission: any;
profile: any;
@@ -340,7 +342,13 @@ export class AddonModWorkshopAssessmentPage implements OnInit, OnDestroy {
// Try to send it to server.
return this.workshopProvider.evaluateAssessment(this.workshopId, this.assessmentId, this.courseId, inputData.text,
- inputData.weight, inputData.grade).then(() => {
+ inputData.weight, inputData.grade).then((result) => {
+
+ this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
+ form: this.formElement.nativeElement,
+ online: !!result,
+ }, this.siteId);
+
const data = {
workshopId: this.workshopId,
assessmentId: this.assessmentId,
diff --git a/src/addon/mod/workshop/pages/edit-submission/edit-submission.html b/src/addon/mod/workshop/pages/edit-submission/edit-submission.html
index a7f3bad68ac..99e4d0bf3c6 100644
--- a/src/addon/mod/workshop/pages/edit-submission/edit-submission.html
+++ b/src/addon/mod/workshop/pages/edit-submission/edit-submission.html
@@ -10,7 +10,7 @@
-
+
{{ 'addon.mod_workshop.submissiontitle' | translate }}
diff --git a/src/addon/mod/workshop/pages/edit-submission/edit-submission.ts b/src/addon/mod/workshop/pages/edit-submission/edit-submission.ts
index c3fb1edbb6f..121d11ed8fb 100644
--- a/src/addon/mod/workshop/pages/edit-submission/edit-submission.ts
+++ b/src/addon/mod/workshop/pages/edit-submission/edit-submission.ts
@@ -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, NavParams, NavController } from 'ionic-angular';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { TranslateService } from '@ngx-translate/core';
@@ -37,6 +37,8 @@ import { AddonModWorkshopOfflineProvider } from '../../providers/offline';
})
export class AddonModWorkshopEditSubmissionPage implements OnInit, OnDestroy {
+ @ViewChild('editFormEl') formElement: ElementRef;
+
module: any;
courseId: number;
access: any;
@@ -352,7 +354,7 @@ export class AddonModWorkshopEditSubmissionPage implements OnInit, OnDestroy {
// Save submission in offline.
return this.workshopOffline.saveSubmission(this.workshopId, this.courseId, inputData.title,
inputData.content, attachmentsId, submissionId, 'update').then(() => {
- // Don't return anything.
+ return false;
});
}
@@ -365,8 +367,8 @@ export class AddonModWorkshopEditSubmissionPage implements OnInit, OnDestroy {
if (saveOffline) {
// Save submission in offline.
return this.workshopOffline.saveSubmission(this.workshopId, this.courseId, inputData.title, inputData.content,
- attachmentsId, submissionId, 'add').then(() => {
- // Don't return anything.
+ attachmentsId, submissionId, 'add').then(() => {
+ return false;
});
}
@@ -375,6 +377,12 @@ export class AddonModWorkshopEditSubmissionPage implements OnInit, OnDestroy {
return this.workshopProvider.addSubmission(this.workshopId, this.courseId, inputData.title, inputData.content,
attachmentsId, undefined, submissionId, allowOffline);
}).then((newSubmissionId) => {
+
+ this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
+ form: this.formElement.nativeElement,
+ online: !!newSubmissionId,
+ }, this.siteId);
+
const data = {
workshopId: this.workshopId,
cmId: this.module.cmid
diff --git a/src/addon/mod/workshop/pages/submission/submission.html b/src/addon/mod/workshop/pages/submission/submission.html
index 0951709aecf..5bff460891d 100644
--- a/src/addon/mod/workshop/pages/submission/submission.html
+++ b/src/addon/mod/workshop/pages/submission/submission.html
@@ -65,7 +65,7 @@ {{ 'addon.mod_workshop.givengrades' | translate }}
-
+
{{ 'addon.mod_workshop.feedbackauthor' | translate }}
diff --git a/src/addon/mod/workshop/pages/submission/submission.ts b/src/addon/mod/workshop/pages/submission/submission.ts
index 3fb884e5f36..a1c3b6d501b 100644
--- a/src/addon/mod/workshop/pages/submission/submission.ts
+++ b/src/addon/mod/workshop/pages/submission/submission.ts
@@ -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 { Content, IonicPage, NavParams, NavController } from 'ionic-angular';
import { FormGroup, FormBuilder } from '@angular/forms';
import { TranslateService } from '@ngx-translate/core';
@@ -41,6 +41,7 @@ import { AddonModWorkshopSyncProvider } from '../../providers/sync';
export class AddonModWorkshopSubmissionPage implements OnInit, OnDestroy {
@ViewChild(AddonModWorkshopAssessmentStrategyComponent) assessmentStrategy: AddonModWorkshopAssessmentStrategyComponent;
+ @ViewChild('feedbackFormEl') formElement: ElementRef;
module: any;
workshop: any;
@@ -444,7 +445,13 @@ export class AddonModWorkshopSubmissionPage implements OnInit, OnDestroy {
// Try to send it to server.
return this.workshopProvider.evaluateSubmission(this.workshopId, this.submissionId, this.courseId, inputData.text,
- inputData.published, inputData.grade).then(() => {
+ inputData.published, inputData.grade).then((result) => {
+
+ this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
+ form: this.formElement.nativeElement,
+ online: !!result,
+ }, this.siteId);
+
const data = {
workshopId: this.workshopId,
cmId: this.module.cmid,
diff --git a/src/addon/notes/pages/add/add.html b/src/addon/notes/pages/add/add.html
index b6df1d660dc..93f2a04a404 100644
--- a/src/addon/notes/pages/add/add.html
+++ b/src/addon/notes/pages/add/add.html
@@ -9,7 +9,7 @@
-
+
{{ 'addon.notes.publishstate' | translate }}
diff --git a/src/addon/notes/pages/add/add.ts b/src/addon/notes/pages/add/add.ts
index 15fd9da0a5d..d00e95aa201 100644
--- a/src/addon/notes/pages/add/add.ts
+++ b/src/addon/notes/pages/add/add.ts
@@ -12,9 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import { Component } from '@angular/core';
+import { Component, ViewChild, ElementRef } from '@angular/core';
import { IonicPage, ViewController, NavParams } from 'ionic-angular';
import { CoreAppProvider } from '@providers/app';
+import { CoreEventsProvider } from '@providers/events';
+import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { AddonNotesProvider } from '../../providers/notes';
@@ -27,14 +29,22 @@ import { AddonNotesProvider } from '../../providers/notes';
templateUrl: 'add.html',
})
export class AddonNotesAddPage {
+
+ @ViewChild('itemEdit') formElement: ElementRef;
+
userId: number;
courseId: number;
type = 'personal';
text = '';
processing = false;
- constructor(params: NavParams, private viewCtrl: ViewController, private appProvider: CoreAppProvider,
- private domUtils: CoreDomUtilsProvider, private notesProvider: AddonNotesProvider) {
+ constructor(params: NavParams,
+ protected viewCtrl: ViewController,
+ protected appProvider: CoreAppProvider,
+ protected domUtils: CoreDomUtilsProvider,
+ protected notesProvider: AddonNotesProvider,
+ protected eventsProvider: CoreEventsProvider,
+ protected sitesProvider: CoreSitesProvider) {
this.userId = params.get('userId');
this.courseId = params.get('courseId');
this.type = params.get('type') || 'personal';
@@ -54,6 +64,12 @@ export class AddonNotesAddPage {
// Freeze the add note button.
this.processing = true;
this.notesProvider.addNote(this.userId, this.courseId, this.type, this.text).then((sent) => {
+
+ this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
+ form: this.formElement.nativeElement,
+ online: sent,
+ }, this.sitesProvider.getCurrentSiteId());
+
this.viewCtrl.dismiss({type: this.type, sent: true}).finally(() => {
this.domUtils.showToast(sent ? 'addon.notes.eventnotecreated' : 'core.datastoredoffline', true, 3000);
});
diff --git a/src/components/local-file/core-local-file.html b/src/components/local-file/core-local-file.html
index a988397a922..ffec36361b3 100644
--- a/src/components/local-file/core-local-file.html
+++ b/src/components/local-file/core-local-file.html
@@ -1,4 +1,4 @@
-
+
diff --git a/src/components/local-file/local-file.ts b/src/components/local-file/local-file.ts
index e1c46b1c2c7..31fd41bf08e 100644
--- a/src/components/local-file/local-file.ts
+++ b/src/components/local-file/local-file.ts
@@ -12,8 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import { Component, Input, Output, OnInit, EventEmitter } from '@angular/core';
+import { Component, Input, Output, OnInit, EventEmitter, ViewChild, ElementRef } from '@angular/core';
+import { CoreEventsProvider } from '@providers/events';
import { CoreFileProvider } from '@providers/file';
+import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreMimetypeUtilsProvider } from '@providers/utils/mimetype';
import { CoreTextUtilsProvider } from '@providers/utils/text';
@@ -38,6 +40,8 @@ export class CoreLocalFileComponent implements OnInit {
@Output() onRename?: EventEmitter; // Will notify when the file is renamed. Receives the FileEntry as the param.
@Output() onClick?: EventEmitter; // Will notify when the file is clicked. Only if overrideClick is true.
+ @ViewChild('nameForm') formElement: ElementRef;
+
fileName: string;
fileIcon: string;
fileExtension: string;
@@ -47,12 +51,14 @@ export class CoreLocalFileComponent implements OnInit {
editMode: boolean;
relativePath: string;
- constructor(private mimeUtils: CoreMimetypeUtilsProvider,
- private utils: CoreUtilsProvider,
- private textUtils: CoreTextUtilsProvider,
- private fileProvider: CoreFileProvider,
- private domUtils: CoreDomUtilsProvider,
- private timeUtils: CoreTimeUtilsProvider) {
+ constructor(protected mimeUtils: CoreMimetypeUtilsProvider,
+ protected utils: CoreUtilsProvider,
+ protected textUtils: CoreTextUtilsProvider,
+ protected fileProvider: CoreFileProvider,
+ protected domUtils: CoreDomUtilsProvider,
+ protected timeUtils: CoreTimeUtilsProvider,
+ protected sitesProvider: CoreSitesProvider,
+ protected eventsProvider: CoreEventsProvider) {
this.onDelete = new EventEmitter();
this.onRename = new EventEmitter();
this.onClick = new EventEmitter();
@@ -152,6 +158,12 @@ export class CoreLocalFileComponent implements OnInit {
}).catch(() => {
// File doesn't exist, move it.
return this.fileProvider.moveFile(this.relativePath, newPath).then((fileEntry) => {
+
+ this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
+ form: this.formElement.nativeElement,
+ online: false,
+ }, this.sitesProvider.getCurrentSiteId());
+
this.editMode = false;
this.file = fileEntry;
this.loadFileBasicData();
diff --git a/src/components/search-box/search-box.ts b/src/components/search-box/search-box.ts
new file mode 100644
index 00000000000..4698e4584a1
--- /dev/null
+++ b/src/components/search-box/search-box.ts
@@ -0,0 +1,100 @@
+// (C) Copyright 2015 Moodle Pty Ltd.
+//
+// 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, Output, EventEmitter, OnInit, ViewChild, ElementRef } from '@angular/core';
+import { TranslateService } from '@ngx-translate/core';
+import { CoreEventsProvider } from '@providers/events';
+import { CoreSitesProvider } from '@providers/sites';
+import { CoreUtilsProvider } from '@providers/utils/utils';
+
+/**
+ * Component to display a "search box".
+ *
+ * @description
+ * This component will display a standalone search box with its search button in order to have a better UX.
+ *
+ * Example usage:
+ *
+ */
+@Component({
+ selector: 'core-search-box',
+ templateUrl: 'core-search-box.html'
+})
+export class CoreSearchBoxComponent implements OnInit {
+ @Input() searchLabel?: string; // Label to be used on action button.
+ @Input() placeholder?: string; // Placeholder text for search text input.
+ @Input() autocorrect = 'on'; // Enables/disable Autocorrection on search text input.
+ @Input() spellcheck?: string | boolean = true; // Enables/disable Spellchecker on search text input.
+ @Input() autoFocus?: string | boolean; // Enables/disable Autofocus when entering view.
+ @Input() lengthCheck = 3; // Check value length before submit. If 0, any string will be submitted.
+ @Input() showClear = true; // Show/hide clear button.
+ @Input() disabled = false; // Disables the input text.
+ @Input() initialSearch: string; // Initial search text.
+ @Output() onSubmit: EventEmitter; // Send data when submitting the search form.
+ @Output() onClear: EventEmitter; // Send event when clearing the search form.
+
+ @ViewChild('searchForm') formElement: ElementRef;
+
+ searched = false;
+ searchText = '';
+
+ constructor(protected translate: TranslateService,
+ protected utils: CoreUtilsProvider,
+ protected eventsProvider: CoreEventsProvider,
+ protected sitesProvider: CoreSitesProvider) {
+ this.onSubmit = new EventEmitter();
+ this.onClear = new EventEmitter();
+ }
+
+ ngOnInit(): void {
+ this.searchLabel = this.searchLabel || this.translate.instant('core.search');
+ this.placeholder = this.placeholder || this.translate.instant('core.search');
+ this.spellcheck = this.utils.isTrueOrOne(this.spellcheck);
+ this.showClear = this.utils.isTrueOrOne(this.showClear);
+ this.searchText = this.initialSearch || '';
+ }
+
+ /**
+ * Form submitted.
+ *
+ * @param e Event.
+ */
+ submitForm(e: Event): void {
+ e.preventDefault();
+ e.stopPropagation();
+
+ if (this.searchText.length < this.lengthCheck) {
+ // The view should handle this case, but we check it here too just in case.
+ return;
+ }
+
+ this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
+ form: this.formElement.nativeElement,
+ online: false,
+ }, this.sitesProvider.getCurrentSiteId());
+
+ this.searched = true;
+ this.onSubmit.emit(this.searchText);
+ }
+
+ /**
+ * Form submitted.
+ */
+ clearForm(): void {
+ this.searched = false;
+ this.searchText = '';
+ this.onClear.emit();
+ }
+}
diff --git a/src/components/send-message-form/core-send-message-form.html b/src/components/send-message-form/core-send-message-form.html
index 8caa886c30b..bed8756ce9a 100644
--- a/src/components/send-message-form/core-send-message-form.html
+++ b/src/components/send-message-form/core-send-message-form.html
@@ -1,4 +1,4 @@
-
+
diff --git a/src/components/send-message-form/send-message-form.ts b/src/components/send-message-form/send-message-form.ts
index 7b5761e390a..147118f7c8f 100644
--- a/src/components/send-message-form/send-message-form.ts
+++ b/src/components/send-message-form/send-message-form.ts
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core';
+import { Component, Input, Output, EventEmitter, OnInit, ViewChild, ElementRef } from '@angular/core';
import { CoreAppProvider } from '@providers/app';
import { CoreConfigProvider } from '@providers/config';
import { CoreEventsProvider } from '@providers/events';
@@ -43,10 +43,16 @@ export class CoreSendMessageFormComponent implements OnInit {
@Output() onSubmit: EventEmitter; // Send data when submitting the message form.
@Output() onResize: EventEmitter; // Emit when resizing the textarea.
+ @ViewChild('messageForm') formElement: ElementRef;
+
protected sendOnEnter: boolean;
- constructor(private utils: CoreUtilsProvider, private textUtils: CoreTextUtilsProvider, configProvider: CoreConfigProvider,
- eventsProvider: CoreEventsProvider, sitesProvider: CoreSitesProvider, private appProvider: CoreAppProvider) {
+ constructor(protected utils: CoreUtilsProvider,
+ protected textUtils: CoreTextUtilsProvider,
+ configProvider: CoreConfigProvider,
+ protected eventsProvider: CoreEventsProvider,
+ protected sitesProvider: CoreSitesProvider,
+ protected appProvider: CoreAppProvider) {
this.onSubmit = new EventEmitter();
this.onResize = new EventEmitter();
@@ -82,6 +88,11 @@ export class CoreSendMessageFormComponent implements OnInit {
this.message = ''; // Reset the form.
+ this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
+ form: this.formElement.nativeElement,
+ online: false,
+ }, this.sitesProvider.getCurrentSiteId());
+
value = this.textUtils.replaceNewLines(value, ' ');
this.onSubmit.emit(value);
}
diff --git a/src/core/comments/pages/add/add.html b/src/core/comments/pages/add/add.html
index b5ca49440af..c3b01e9b2da 100644
--- a/src/core/comments/pages/add/add.html
+++ b/src/core/comments/pages/add/add.html
@@ -9,7 +9,7 @@
-
+
diff --git a/src/core/comments/pages/add/add.ts b/src/core/comments/pages/add/add.ts
index 4141091389b..583cb0300dd 100644
--- a/src/core/comments/pages/add/add.ts
+++ b/src/core/comments/pages/add/add.ts
@@ -12,9 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import { Component } from '@angular/core';
+import { Component, ViewChild, ElementRef } from '@angular/core';
import { IonicPage, ViewController, NavParams } from 'ionic-angular';
import { CoreAppProvider } from '@providers/app';
+import { CoreEventsProvider } from '@providers/events';
+import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreCommentsProvider } from '../../providers/comments';
@@ -27,6 +29,8 @@ import { CoreCommentsProvider } from '../../providers/comments';
templateUrl: 'add.html',
})
export class CoreCommentsAddPage {
+ @ViewChild('commentForm') formElement: ElementRef;
+
protected contextLevel: string;
protected instanceId: number;
protected componentName: string;
@@ -36,8 +40,13 @@ export class CoreCommentsAddPage {
content = '';
processing = false;
- constructor(params: NavParams, private viewCtrl: ViewController, private appProvider: CoreAppProvider,
- private domUtils: CoreDomUtilsProvider, private commentsProvider: CoreCommentsProvider) {
+ constructor(params: NavParams,
+ protected viewCtrl: ViewController,
+ protected appProvider: CoreAppProvider,
+ protected domUtils: CoreDomUtilsProvider,
+ protected commentsProvider: CoreCommentsProvider,
+ protected eventsProvider: CoreEventsProvider,
+ protected sitesProvider: CoreSitesProvider) {
this.contextLevel = params.get('contextLevel');
this.instanceId = params.get('instanceId');
this.componentName = params.get('componentName');
@@ -61,6 +70,12 @@ export class CoreCommentsAddPage {
this.processing = true;
this.commentsProvider.addComment(this.content, this.contextLevel, this.instanceId, this.componentName, this.itemId,
this.area).then((commentsResponse) => {
+
+ this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
+ form: this.formElement.nativeElement,
+ online: !!commentsResponse,
+ }, this.sitesProvider.getCurrentSiteId());
+
this.viewCtrl.dismiss({comments: commentsResponse}).finally(() => {
this.domUtils.showToast(commentsResponse ? 'core.comments.eventcommentcreated' : 'core.datastoredoffline', true,
3000);
diff --git a/src/core/comments/providers/comments.ts b/src/core/comments/providers/comments.ts
index 960e6688b25..3dc4a001607 100644
--- a/src/core/comments/providers/comments.ts
+++ b/src/core/comments/providers/comments.ts
@@ -54,7 +54,7 @@ export class CoreCommentsProvider {
// Convenience function to store a comment to be synchronized later.
const storeOffline = (): Promise => {
return this.commentsOffline.saveComment(content, contextLevel, instanceId, component, itemId, area, siteId).then(() => {
- return Promise.resolve(false);
+ return false;
});
};
diff --git a/src/core/courses/pages/self-enrol-password/self-enrol-password.html b/src/core/courses/pages/self-enrol-password/self-enrol-password.html
index 3617c7dc335..1ca665964a0 100644
--- a/src/core/courses/pages/self-enrol-password/self-enrol-password.html
+++ b/src/core/courses/pages/self-enrol-password/self-enrol-password.html
@@ -10,7 +10,7 @@
-
+
diff --git a/src/core/courses/pages/self-enrol-password/self-enrol-password.ts b/src/core/courses/pages/self-enrol-password/self-enrol-password.ts
index a646dacb4b0..c95c5ec83b6 100644
--- a/src/core/courses/pages/self-enrol-password/self-enrol-password.ts
+++ b/src/core/courses/pages/self-enrol-password/self-enrol-password.ts
@@ -12,8 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import { Component } from '@angular/core';
+import { Component, ViewChild, ElementRef } from '@angular/core';
import { IonicPage, ViewController } from 'ionic-angular';
+import { CoreEventsProvider } from '@providers/events';
+import { CoreSitesProvider } from '@providers/sites';
/**
* Page that displays a form to enter a password to self enrol in a course.
@@ -24,7 +26,12 @@ import { IonicPage, ViewController } from 'ionic-angular';
templateUrl: 'self-enrol-password.html',
})
export class CoreCoursesSelfEnrolPasswordPage {
- constructor(private viewCtrl: ViewController) { }
+
+ @ViewChild('enrolPasswordForm') formElement: ElementRef;
+
+ constructor(protected viewCtrl: ViewController,
+ protected eventsProvider: CoreEventsProvider,
+ protected sitesProvider: CoreSitesProvider) { }
/**
* Close help modal.
@@ -43,6 +50,11 @@ export class CoreCoursesSelfEnrolPasswordPage {
e.preventDefault();
e.stopPropagation();
+ this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
+ form: this.formElement.nativeElement,
+ online: false,
+ }, this.sitesProvider.getCurrentSiteId());
+
this.viewCtrl.dismiss(password);
}
}
diff --git a/src/core/editor/components/rich-text-editor/rich-text-editor.ts b/src/core/editor/components/rich-text-editor/rich-text-editor.ts
index 3920542026d..dc79617c3f8 100644
--- a/src/core/editor/components/rich-text-editor/rich-text-editor.ts
+++ b/src/core/editor/components/rich-text-editor/rich-text-editor.ts
@@ -67,7 +67,8 @@ export class CoreEditorRichTextEditorComponent implements AfterContentInit, OnDe
protected valueChangeSubscription: Subscription;
protected keyboardObs: any;
- protected initHeightInterval;
+ protected resetObs: any;
+ protected initHeightInterval: NodeJS.Timer;
rteEnabled = false;
editorSupported = true;
@@ -175,11 +176,11 @@ export class CoreEditorRichTextEditorComponent implements AfterContentInit, OnDe
}
if (this.shouldAutoSaveDrafts()) {
- // Recover drafts.
this.restoreDraft();
- // Auto save drafts every certain time.
this.autoSaveDrafts();
+
+ this.deleteDraftOnSubmit();
}
}
@@ -780,6 +781,25 @@ export class CoreEditorRichTextEditorComponent implements AfterContentInit, OnDe
}, this.DRAFT_AUTOSAVE_FREQUENCY);
}
+ /**
+ * Delete the draft when the form is submitted.
+ */
+ protected deleteDraftOnSubmit(): void {
+
+ this.resetObs = this.events.on(CoreEventsProvider.FORM_SUBMITTED, async (data) => {
+ const form = this.element.closest('form');
+
+ if (data.form && form && data.form == form) {
+ try {
+ await this.editorOffline.deleteDraft(this.contextLevel, this.contextInstanceId, this.elementId,
+ this.draftExtraParams);
+ } catch (error) {
+ // Error deleting draft. Shouldn't happen.
+ }
+ }
+ }, this.sitesProvider.getCurrentSiteId());
+ }
+
/**
* Show a message.
*
@@ -824,5 +844,6 @@ export class CoreEditorRichTextEditorComponent implements AfterContentInit, OnDe
this.keyboardObs && this.keyboardObs.off();
clearInterval(this.autoSaveInterval);
clearTimeout(this.hideMessageTimeout);
+ this.resetObs && this.resetObs.off();
}
}
diff --git a/src/core/login/pages/credentials/credentials.html b/src/core/login/pages/credentials/credentials.html
index a1b2f106973..cff98e8b5eb 100644
--- a/src/core/login/pages/credentials/credentials.html
+++ b/src/core/login/pages/credentials/credentials.html
@@ -23,7 +23,7 @@
{{siteUrl}}
-
+
diff --git a/src/core/login/pages/credentials/credentials.ts b/src/core/login/pages/credentials/credentials.ts
index 13b81d12c57..3d3f6f5e4d8 100644
--- a/src/core/login/pages/credentials/credentials.ts
+++ b/src/core/login/pages/credentials/credentials.ts
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import { Component } from '@angular/core';
+import { Component, ViewChild, ElementRef } from '@angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app';
@@ -32,6 +32,9 @@ import { CoreConfigConstants } from '../../../../configconstants';
templateUrl: 'credentials.html',
})
export class CoreLoginCredentialsPage {
+
+ @ViewChild('credentialsForm') formElement: ElementRef;
+
credForm: FormGroup;
siteUrl: string;
siteChecked = false;
@@ -242,6 +245,11 @@ export class CoreLoginCredentialsPage {
}
}).finally(() => {
modal.dismiss();
+
+ this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
+ form: this.formElement.nativeElement,
+ online: true,
+ });
});
}
diff --git a/src/core/login/pages/email-signup/email-signup.html b/src/core/login/pages/email-signup/email-signup.html
index 2e49ea82287..3e52b4b6ce2 100644
--- a/src/core/login/pages/email-signup/email-signup.html
+++ b/src/core/login/pages/email-signup/email-signup.html
@@ -17,7 +17,7 @@
-
+
{{ 'core.agelocationverification' | translate }}
@@ -47,7 +47,7 @@
-
+
{{siteUrl}}
diff --git a/src/core/login/pages/email-signup/email-signup.ts b/src/core/login/pages/email-signup/email-signup.ts
index ffb8a6f425f..e9563da5928 100644
--- a/src/core/login/pages/email-signup/email-signup.ts
+++ b/src/core/login/pages/email-signup/email-signup.ts
@@ -12,9 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import { Component, ViewChild } from '@angular/core';
+import { Component, ViewChild, ElementRef } from '@angular/core';
import { IonicPage, NavController, NavParams, Content } 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 { CoreTextUtilsProvider } from '@providers/utils/text';
@@ -35,6 +36,8 @@ import { CoreConfigConstants } from '../../../../configconstants';
})
export class CoreLoginEmailSignupPage {
@ViewChild(Content) content: Content;
+ @ViewChild('ageForm') ageFormElement: ElementRef;
+ @ViewChild('signupFormEl') signupFormElement: ElementRef;
signupForm: FormGroup;
siteUrl: string;
@@ -66,10 +69,18 @@ export class CoreLoginEmailSignupPage {
policyErrors: any;
namefieldsErrors: any;
- constructor(private navCtrl: NavController, navParams: NavParams, private fb: FormBuilder, private wsProvider: CoreWSProvider,
- private sitesProvider: CoreSitesProvider, private loginHelper: CoreLoginHelperProvider,
- private domUtils: CoreDomUtilsProvider, private translate: TranslateService, private utils: CoreUtilsProvider,
- private textUtils: CoreTextUtilsProvider, private userProfileFieldDelegate: CoreUserProfileFieldDelegate) {
+ constructor(protected navCtrl: NavController,
+ navParams: NavParams,
+ protected fb: FormBuilder,
+ protected wsProvider: CoreWSProvider,
+ protected sitesProvider: CoreSitesProvider,
+ protected loginHelper: CoreLoginHelperProvider,
+ protected domUtils: CoreDomUtilsProvider,
+ protected translate: TranslateService,
+ protected utils: CoreUtilsProvider,
+ protected textUtils: CoreTextUtilsProvider,
+ protected userProfileFieldDelegate: CoreUserProfileFieldDelegate,
+ protected eventsProvider: CoreEventsProvider) {
this.siteUrl = navParams.get('siteUrl');
@@ -265,6 +276,12 @@ export class CoreLoginEmailSignupPage {
return this.wsProvider.callAjax('auth_email_signup_user', params, { siteUrl: this.siteUrl });
}).then((result) => {
if (result.success) {
+
+ this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
+ form: this.signupFormElement.nativeElement,
+ online: true,
+ });
+
// Show alert and ho back.
const message = this.translate.instant('core.login.emailconfirmsent', { $a: params.email });
this.domUtils.showAlert(this.translate.instant('core.success'), message);
@@ -334,6 +351,12 @@ export class CoreLoginEmailSignupPage {
params.age = parseInt(params.age, 10); // Use just the integer part.
this.wsProvider.callAjax('core_auth_is_minor', params, {siteUrl: this.siteUrl}).then((result) => {
+
+ this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
+ form: this.ageFormElement.nativeElement,
+ online: true,
+ });
+
if (!result.status) {
if (this.countryControl.value) {
this.signUpCountryControl.setValue(this.countryControl.value);
diff --git a/src/core/login/pages/forgotten-password/forgotten-password.html b/src/core/login/pages/forgotten-password/forgotten-password.html
index 182ef231289..81905e4d40a 100644
--- a/src/core/login/pages/forgotten-password/forgotten-password.html
+++ b/src/core/login/pages/forgotten-password/forgotten-password.html
@@ -10,7 +10,7 @@
-
+
{{ 'core.login.searchby' | translate }}
diff --git a/src/core/login/pages/forgotten-password/forgotten-password.ts b/src/core/login/pages/forgotten-password/forgotten-password.ts
index b1d5d6785b5..1187d903ac2 100644
--- a/src/core/login/pages/forgotten-password/forgotten-password.ts
+++ b/src/core/login/pages/forgotten-password/forgotten-password.ts
@@ -12,9 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import { Component } from '@angular/core';
+import { Component, ViewChild, ElementRef } from '@angular/core';
import { IonicPage, NavController, 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 { CoreLoginHelperProvider } from '../../providers/helper';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
@@ -28,11 +30,20 @@ import { FormBuilder, FormGroup, Validators } from '@angular/forms';
templateUrl: 'forgotten-password.html',
})
export class CoreLoginForgottenPasswordPage {
+
+ @ViewChild('resetPasswordForm') formElement: ElementRef;
+
myForm: FormGroup;
siteUrl: string;
- constructor(private navCtrl: NavController, navParams: NavParams, fb: FormBuilder, private translate: TranslateService,
- private loginHelper: CoreLoginHelperProvider, private domUtils: CoreDomUtilsProvider) {
+ constructor(protected navCtrl: NavController,
+ navParams: NavParams,
+ fb: FormBuilder,
+ protected translate: TranslateService,
+ protected loginHelper: CoreLoginHelperProvider,
+ protected domUtils: CoreDomUtilsProvider,
+ protected eventsProvider: CoreEventsProvider,
+ protected sitesProvider: CoreSitesProvider) {
this.siteUrl = navParams.get('siteUrl');
this.myForm = fb.group({
@@ -71,6 +82,11 @@ export class CoreLoginForgottenPasswordPage {
this.domUtils.showErrorModal(response.notice);
} else {
// Success.
+ this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
+ form: this.formElement.nativeElement,
+ online: true,
+ });
+
this.domUtils.showAlert(this.translate.instant('core.success'), response.notice);
this.navCtrl.pop();
}
diff --git a/src/core/login/pages/reconnect/reconnect.html b/src/core/login/pages/reconnect/reconnect.html
index bfb460784bc..1b87186ee02 100644
--- a/src/core/login/pages/reconnect/reconnect.html
+++ b/src/core/login/pages/reconnect/reconnect.html
@@ -29,7 +29,7 @@
{{ 'core.login.reconnectdescription' | translate }}
-
+
{{username}}
diff --git a/src/core/login/pages/reconnect/reconnect.ts b/src/core/login/pages/reconnect/reconnect.ts
index 9372ed2b7d7..73b5515748b 100644
--- a/src/core/login/pages/reconnect/reconnect.ts
+++ b/src/core/login/pages/reconnect/reconnect.ts
@@ -12,9 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import { Component } from '@angular/core';
+import { Component, ViewChild, ElementRef } from '@angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
import { CoreAppProvider } from '@providers/app';
+import { CoreEventsProvider } from '@providers/events';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreLoginHelperProvider } from '../../providers/helper';
@@ -29,6 +30,9 @@ import { FormBuilder, FormGroup, Validators } from '@angular/forms';
templateUrl: 'reconnect.html',
})
export class CoreLoginReconnectPage {
+
+ @ViewChild('reconnectForm') formElement: ElementRef;
+
credForm: FormGroup;
siteUrl: string;
username: string;
@@ -47,13 +51,14 @@ export class CoreLoginReconnectPage {
protected isLoggedOut: boolean;
protected siteId: string;
- constructor(private navCtrl: NavController,
+ constructor(protected navCtrl: NavController,
navParams: NavParams,
fb: FormBuilder,
- private appProvider: CoreAppProvider,
- private sitesProvider: CoreSitesProvider,
- private loginHelper: CoreLoginHelperProvider,
- private domUtils: CoreDomUtilsProvider) {
+ protected appProvider: CoreAppProvider,
+ protected sitesProvider: CoreSitesProvider,
+ protected loginHelper: CoreLoginHelperProvider,
+ protected domUtils: CoreDomUtilsProvider,
+ protected eventsProvider: CoreEventsProvider) {
const currentSite = this.sitesProvider.getCurrentSite();
@@ -175,6 +180,12 @@ export class CoreLoginReconnectPage {
// Start the authentication process.
this.sitesProvider.getUserToken(siteUrl, username, password).then((data) => {
return this.sitesProvider.updateSiteToken(this.infoSiteUrl, username, data.token, data.privateToken).then(() => {
+
+ this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
+ form: this.formElement.nativeElement,
+ online: true,
+ });
+
// Update site info too because functions might have changed (e.g. unisntall local_mobile).
return this.sitesProvider.updateSiteInfoByUrl(this.infoSiteUrl, username).then(() => {
// Reset fields so the data is not in the view anymore.
diff --git a/src/core/login/pages/site/site.html b/src/core/login/pages/site/site.html
index 6a4b40f36cf..8da75c237ec 100644
--- a/src/core/login/pages/site/site.html
+++ b/src/core/login/pages/site/site.html
@@ -17,7 +17,7 @@
-
+
{{ 'core.login.newsitedescription' | translate }}
diff --git a/src/core/login/pages/site/site.ts b/src/core/login/pages/site/site.ts
index 5a231d27c1d..d20b510f774 100644
--- a/src/core/login/pages/site/site.ts
+++ b/src/core/login/pages/site/site.ts
@@ -12,9 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import { Component } from '@angular/core';
+import { Component, ViewChild, ElementRef } from '@angular/core';
import { IonicPage, NavController, ModalController, NavParams } from 'ionic-angular';
import { CoreAppProvider } from '@providers/app';
+import { CoreEventsProvider } from '@providers/events';
import { CoreSitesProvider, CoreSiteCheckResponse } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreConfigConstants } from '../../../../configconstants';
@@ -31,6 +32,9 @@ import { CoreUrl } from '@classes/utils/url';
templateUrl: 'site.html',
})
export class CoreLoginSitePage {
+
+ @ViewChild('siteFormEl') formElement: ElementRef;
+
siteForm: FormGroup;
fixedSites: any[];
filteredSites: any[];
@@ -38,9 +42,15 @@ export class CoreLoginSitePage {
showKeyboard = false;
filter = '';
- constructor(navParams: NavParams, private navCtrl: NavController, fb: FormBuilder, private appProvider: CoreAppProvider,
- private sitesProvider: CoreSitesProvider, private loginHelper: CoreLoginHelperProvider,
- private modalCtrl: ModalController, private domUtils: CoreDomUtilsProvider) {
+ constructor(navParams: NavParams,
+ protected navCtrl: NavController,
+ fb: FormBuilder,
+ protected appProvider: CoreAppProvider,
+ protected sitesProvider: CoreSitesProvider,
+ protected loginHelper: CoreLoginHelperProvider,
+ protected modalCtrl: ModalController,
+ protected domUtils: CoreDomUtilsProvider,
+ protected eventsProvider: CoreEventsProvider) {
this.showKeyboard = !!navParams.get('showKeyboard');
@@ -96,6 +106,12 @@ export class CoreLoginSitePage {
// It's a demo site.
this.sitesProvider.getUserToken(siteData.url, siteData.username, siteData.password).then((data) => {
return this.sitesProvider.newSite(data.siteUrl, data.token, data.privateToken).then(() => {
+
+ this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
+ form: this.formElement.nativeElement,
+ online: true,
+ });
+
return this.loginHelper.goToSiteInitialPage();
}, (error) => {
this.loginHelper.treatUserTokenError(siteData.url, error, siteData.username, siteData.password);
@@ -175,6 +191,12 @@ export class CoreLoginSitePage {
*/
protected async login(response: CoreSiteCheckResponse): Promise {
return this.sitesProvider.checkRequiredMinimumVersion(response.config).then(() => {
+
+ this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
+ form: this.formElement.nativeElement,
+ online: true,
+ });
+
if (response.warning) {
this.domUtils.showErrorModal(response.warning, true, 4000);
}
diff --git a/src/core/search/components/search-box/core-search-box.html b/src/core/search/components/search-box/core-search-box.html
index adc00c50b72..be186a40bf4 100644
--- a/src/core/search/components/search-box/core-search-box.html
+++ b/src/core/search/components/search-box/core-search-box.html
@@ -1,5 +1,5 @@
-
+
diff --git a/src/core/search/components/search-box/search-box.ts b/src/core/search/components/search-box/search-box.ts
index da5223e377e..1f1ec4d915b 100644
--- a/src/core/search/components/search-box/search-box.ts
+++ b/src/core/search/components/search-box/search-box.ts
@@ -12,8 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import { Component, Input, Output, EventEmitter, OnInit, OnDestroy } from '@angular/core';
+import { Component, Input, Output, EventEmitter, OnInit, OnDestroy, ViewChild, ElementRef } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
+import { CoreEventsProvider } from '@providers/events';
+import { CoreSitesProvider } from '@providers/sites';
+import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreSearchHistoryProvider, CoreSearchHistoryItem } from '../../providers/search-history';
@@ -47,6 +50,8 @@ export class CoreSearchBoxComponent implements OnInit, OnDestroy {
@Output() onSubmit: EventEmitter; // Send data when submitting the search form.
@Output() onClear: EventEmitter; // Send event when clearing the search form.
+ @ViewChild('searchForm') formElement: ElementRef;
+
searched = ''; // Last search emitted.
searchText = '';
history: CoreSearchHistoryItem[];
@@ -58,6 +63,9 @@ export class CoreSearchBoxComponent implements OnInit, OnDestroy {
constructor(protected translate: TranslateService,
protected utils: CoreUtilsProvider,
protected searchHistoryProvider: CoreSearchHistoryProvider,
+ protected eventsProvider: CoreEventsProvider,
+ protected sitesProvider: CoreSitesProvider,
+ protected domUtils: CoreDomUtilsProvider,
) {
this.onSubmit = new EventEmitter();
this.onClear = new EventEmitter();
@@ -95,6 +103,8 @@ export class CoreSearchBoxComponent implements OnInit, OnDestroy {
this.saveSearchToHistory(this.searchText);
}
+ this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, false, this.sitesProvider.getCurrentSiteId());
+
this.searched = this.searchText;
this.onSubmit.emit(this.searchText);
}
diff --git a/src/providers/events.ts b/src/providers/events.ts
index 5d1557ed880..d20103e8816 100644
--- a/src/providers/events.ts
+++ b/src/providers/events.ts
@@ -64,6 +64,7 @@ export class CoreEventsProvider {
static SELECT_COURSE_TAB = 'select_course_tab';
static WS_CACHE_INVALIDATED = 'ws_cache_invalidated';
static SITE_STORAGE_DELETED = 'site_storage_deleted';
+ static FORM_SUBMITTED = 'form_submitted';
protected logger;
protected observables: { [s: string]: Subject } = {};
From 0fcdd494de25e5b230b3ab85f14896d5fc660393 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?=
Date: Thu, 6 Feb 2020 12:19:09 +0100
Subject: [PATCH 5/9] MOBILE-3323 rte: Style draft messages
---
.../core-editor-rich-text-editor.html | 2 +-
.../rich-text-editor/rich-text-editor.scss | 20 ++++++++++++-------
.../rich-text-editor/rich-text-editor.ts | 17 ++++++++++++++--
3 files changed, 29 insertions(+), 10 deletions(-)
diff --git a/src/core/editor/components/rich-text-editor/core-editor-rich-text-editor.html b/src/core/editor/components/rich-text-editor/core-editor-rich-text-editor.html
index 6b3a503edcb..69775a45d82 100644
--- a/src/core/editor/components/rich-text-editor/core-editor-rich-text-editor.html
+++ b/src/core/editor/components/rich-text-editor/core-editor-rich-text-editor.html
@@ -1,4 +1,4 @@
-
+
diff --git a/src/core/editor/components/rich-text-editor/rich-text-editor.scss b/src/core/editor/components/rich-text-editor/rich-text-editor.scss
index 5b929a3cf91..ae01ced74e2 100644
--- a/src/core/editor/components/rich-text-editor/rich-text-editor.scss
+++ b/src/core/editor/components/rich-text-editor/rich-text-editor.scss
@@ -11,15 +11,20 @@ ion-app.app-root core-rich-text-editor {
}
.core-rte-editor-container {
- height: 100%;
- position: relative;
+ max-height: calc(100% - 46px);
+ display: flex;
+ flex-direction: column;
+ flex-grow: 1;
+ &.toolbar-hidden {
+ max-height: 100%;
+ }
.core-rte-info-message {
- position: absolute;
- bottom: 0;
- padding: 3px;
- border: 1px solid $info;
- border-radius: 5px;
+ padding: 5px;
+ border-top: 1px solid $info;
+ background: white;
+ flex-shrink: 1;
+ font-size: 1.4rem;
.icon {
color: $info;
@@ -33,6 +38,7 @@ ion-app.app-root core-rich-text-editor {
width: 100%;
resize: none;
background-color: $white;
+ flex-grow: 1;
@include darkmode() {
background-color: $gray-darker;
color: $white;
diff --git a/src/core/editor/components/rich-text-editor/rich-text-editor.ts b/src/core/editor/components/rich-text-editor/rich-text-editor.ts
index dc79617c3f8..c619aaf0016 100644
--- a/src/core/editor/components/rich-text-editor/rich-text-editor.ts
+++ b/src/core/editor/components/rich-text-editor/rich-text-editor.ts
@@ -230,7 +230,7 @@ export class CoreEditorRichTextEditorComponent implements AfterContentInit, OnDe
}
if (height > this.minHeight) {
- this.element.style.height = this.domUtils.formatPixelsSize(height);
+ this.element.style.height = this.domUtils.formatPixelsSize(height - 1);
} else {
this.element.style.height = '';
}
@@ -583,10 +583,23 @@ export class CoreEditorRichTextEditorComponent implements AfterContentInit, OnDe
}
}
+ /**
+ * Focus editor when click the area.
+ *
+ * @param e Event
+ */
+ focusRTE(e?: Event): void {
+ if (this.rteEnabled) {
+ this.editorElement.focus();
+ } else {
+ this.textarea.setFocus();
+ }
+ }
+
/**
* Hide the toolbar in phone mode.
*/
- hideToolbar($event: any): void {
+ hideToolbar($event: Event): void {
this.stopBubble($event);
if (this.isPhone) {
From 90f96b762be4feec141699b3d8003619e694dd37 Mon Sep 17 00:00:00 2001
From: Dani Palou
Date: Fri, 7 Feb 2020 10:22:59 +0100
Subject: [PATCH 6/9] MOBILE-3323 editor: Store editor original content to
detect changes
---
.../rich-text-editor/rich-text-editor.ts | 33 +++++++++---
src/core/editor/providers/editor-offline.ts | 51 ++++++++++++++-----
2 files changed, 63 insertions(+), 21 deletions(-)
diff --git a/src/core/editor/components/rich-text-editor/rich-text-editor.ts b/src/core/editor/components/rich-text-editor/rich-text-editor.ts
index c619aaf0016..2fa0bc6131f 100644
--- a/src/core/editor/components/rich-text-editor/rich-text-editor.ts
+++ b/src/core/editor/components/rich-text-editor/rich-text-editor.ts
@@ -103,6 +103,7 @@ export class CoreEditorRichTextEditorComponent implements AfterContentInit, OnDe
protected hideMessageTimeout: NodeJS.Timer;
protected lastDraft = '';
protected draftWasRestored = false;
+ protected originalContent: string;
constructor(
protected domUtils: CoreDomUtilsProvider,
@@ -133,6 +134,8 @@ export class CoreEditorRichTextEditorComponent implements AfterContentInit, OnDe
// Setup the editor.
this.editorElement = this.editor.nativeElement as HTMLDivElement;
this.setContent(this.control.value);
+ this.originalContent = this.control.value;
+ this.lastDraft = this.control.value;
this.editorElement.onchange = this.onChange.bind(this);
this.editorElement.onkeyup = this.onChange.bind(this);
this.editorElement.onpaste = this.onChange.bind(this);
@@ -141,8 +144,19 @@ export class CoreEditorRichTextEditorComponent implements AfterContentInit, OnDe
// Listen for changes on the control to update the editor (if it is updated from outside of this component).
this.valueChangeSubscription = this.control.valueChanges.subscribe((param) => {
- if (!this.draftWasRestored) {
+ if (!this.draftWasRestored || this.originalContent != param) {
+ // Apply the new content.
this.setContent(param);
+ this.originalContent = param;
+ this.infoMessage = null;
+
+ // Save a draft so the original content is saved.
+ this.lastDraft = param;
+ this.editorOffline.saveDraft(this.contextLevel, this.contextInstanceId, this.elementId,
+ this.draftExtraParams, this.pageInstance, param, param);
+ } else {
+ // A draft was restored and the content hasn't changed in the site. Use the draft value instead of this one.
+ this.control.setValue(this.lastDraft, {emitEvent: false});
}
});
@@ -740,14 +754,16 @@ export class CoreEditorRichTextEditorComponent implements AfterContentInit, OnDe
*/
protected async restoreDraft(): Promise {
try {
- let draftText = await this.editorOffline.resumeDraft(this.contextLevel, this.contextInstanceId, this.elementId,
- this.draftExtraParams, this.pageInstance);
+ const entry = await this.editorOffline.resumeDraft(this.contextLevel, this.contextInstanceId, this.elementId,
+ this.draftExtraParams, this.pageInstance, this.originalContent);
- if (typeof draftText == 'undefined') {
+ if (typeof entry == 'undefined') {
// No draft found.
return;
}
+ let draftText = entry.drafttext;
+
// Revert untouched editor contents to an empty string.
if (draftText == '
' || draftText == '
' || draftText == ' ' ||
draftText == '
' || draftText == '
') {
@@ -760,9 +776,12 @@ export class CoreEditorRichTextEditorComponent implements AfterContentInit, OnDe
this.setContent(draftText);
this.lastDraft = draftText;
this.draftWasRestored = true;
+ this.originalContent = entry.originalcontent;
- // Notify the user.
- this.showMessage('core.editor.textrecovered', this.RESTORE_MESSAGE_CLEAR_TIME);
+ if (entry.drafttext != entry.originalcontent) {
+ // Notify the user.
+ this.showMessage('core.editor.textrecovered', this.RESTORE_MESSAGE_CLEAR_TIME);
+ }
}
} catch (error) {
// Ignore errors, shouldn't happen.
@@ -783,7 +802,7 @@ export class CoreEditorRichTextEditorComponent implements AfterContentInit, OnDe
try {
await this.editorOffline.saveDraft(this.contextLevel, this.contextInstanceId, this.elementId,
- this.draftExtraParams, this.pageInstance, newText);
+ this.draftExtraParams, this.pageInstance, newText, this.originalContent);
// Draft saved, notify the user.
this.lastDraft = newText;
diff --git a/src/core/editor/providers/editor-offline.ts b/src/core/editor/providers/editor-offline.ts
index 0f0b5e28cbf..17d8b44ce49 100644
--- a/src/core/editor/providers/editor-offline.ts
+++ b/src/core/editor/providers/editor-offline.ts
@@ -53,25 +53,29 @@ export class CoreEditorOfflineProvider {
{
name: 'drafttext',
type: 'TEXT',
- notNull: true
+ notNull: true,
},
{
name: 'pageinstance',
type: 'TEXT',
- notNull: true
+ notNull: true,
},
{
name: 'timecreated',
type: 'INTEGER',
- notNull: true
+ notNull: true,
},
{
name: 'timemodified',
type: 'INTEGER',
- notNull: true
+ notNull: true,
+ },
+ {
+ name: 'originalcontent',
+ type: 'TEXT',
},
],
- primaryKeys: ['contextlevel', 'contextinstanceid', 'elementid', 'extraparams']
+ primaryKeys: ['contextlevel', 'contextinstanceid', 'elementid', 'extraparams'],
},
],
};
@@ -158,11 +162,12 @@ export class CoreEditorOfflineProvider {
* @param elementId Element ID.
* @param extraParams Object with extra params to identify the draft.
* @param pageInstance Unique identifier to prevent storing data from several sources at the same time.
+ * @param originalContent Original content of the editor.
* @param siteId Site ID. If not defined, current site.
- * @return Promise resolved with the draft text. Undefined if no draft stored.
+ * @return Promise resolved with the draft data. Undefined if no draft stored.
*/
async resumeDraft(contextLevel: string, contextInstanceId: number, elementId: string, extraParams: {[name: string]: any},
- pageInstance: string, siteId?: string): Promise {
+ pageInstance: string, originalContent?: string, siteId?: string): Promise {
try {
// Check if there is a draft stored.
@@ -175,15 +180,21 @@ export class CoreEditorOfflineProvider {
entry.pageinstance = pageInstance;
entry.timemodified = Date.now();
+ if (originalContent && entry.originalcontent != originalContent) {
+ entry.originalcontent = originalContent;
+ entry.drafttext = ''; // "Discard" the draft.
+ }
+
await db.insertRecord(this.DRAFT_TABLE, entry);
} catch (error) {
// Ignore errors saving the draft. It shouldn't happen.
}
- return entry.drafttext;
+ return entry;
} catch (error) {
// No draft stored. Store an empty draft to save the pageinstance.
- await this.saveDraft(contextLevel, contextInstanceId, elementId, extraParams, pageInstance, '', siteId);
+ await this.saveDraft(contextLevel, contextInstanceId, elementId, extraParams, pageInstance, '', originalContent,
+ siteId);
}
}
@@ -196,11 +207,12 @@ export class CoreEditorOfflineProvider {
* @param extraParams Object with extra params to identify the draft.
* @param pageInstance Unique identifier to prevent storing data from several sources at the same time.
* @param draftText The text to store.
+ * @param originalContent Original content of the editor.
* @param siteId Site ID. If not defined, current site.
* @return Promise resolved when done.
*/
async saveDraft(contextLevel: string, contextInstanceId: number, elementId: string, extraParams: {[name: string]: any},
- pageInstance: string, draftText: string, siteId?: string): Promise {
+ pageInstance: string, draftText: string, originalContent?: string, siteId?: string): Promise {
let timecreated = Date.now();
let entry: CoreEditorDraft;
@@ -214,10 +226,17 @@ export class CoreEditorOfflineProvider {
// No draft already stored.
}
- if (entry && entry.pageinstance != pageInstance) {
- this.logger.warning(`Discarding draft because of pageinstance. Context '${contextLevel}' '${contextInstanceId}', ` +
- `element '${elementId}'`);
- throw null;
+ if (entry) {
+ if (entry.pageinstance != pageInstance) {
+ this.logger.warning(`Discarding draft because of pageinstance. Context '${contextLevel}' '${contextInstanceId}', ` +
+ `element '${elementId}'`);
+ throw null;
+ }
+
+ if (!originalContent) {
+ // Original content not set, use the one in the entry.
+ originalContent = entry.originalcontent;
+ }
}
const db = await this.sitesProvider.getSiteDb(siteId);
@@ -228,6 +247,9 @@ export class CoreEditorOfflineProvider {
data.pageinstance = pageInstance;
data.timecreated = timecreated;
data.timemodified = Date.now();
+ if (originalContent) {
+ data.originalcontent = originalContent;
+ }
await db.insertRecord(this.DRAFT_TABLE, data);
}
@@ -251,4 +273,5 @@ type CoreEditorDraft = CoreEditorDraftPrimaryData & {
pageinstance?: string; // Unique identifier to prevent storing data from several sources at the same time.
timecreated?: number; // Time created.
timemodified?: number; // Time modified.
+ originalcontent?: string; // Original content of the editor.
};
From 3ab2e7ddc0ee44d30474e37e06f8272dc228b72a Mon Sep 17 00:00:00 2001
From: Dani Palou
Date: Fri, 7 Feb 2020 13:19:58 +0100
Subject: [PATCH 7/9] MOBILE-3323 editor: Discard draft when user cancels
---
.../calendar/pages/edit-event/edit-event.ts | 20 ++++---
.../edit-feedback-modal.ts | 20 +++----
src/addon/mod/assign/pages/edit/edit.ts | 26 ++++-----
src/addon/mod/data/pages/edit/edit.ts | 32 +++++-----
src/addon/mod/data/pages/search/search.ts | 11 ++--
.../mod/lesson/components/index/index.ts | 6 +-
.../pages/password-modal/password-modal.ts | 11 ++--
src/addon/mod/lesson/pages/player/player.ts | 14 ++---
src/addon/mod/quiz/pages/player/player.ts | 24 ++++----
.../pages/preflight-modal/preflight-modal.ts | 7 +--
src/addon/mod/wiki/pages/edit/edit.ts | 20 +++----
.../assessment-strategy.ts | 5 +-
.../workshop/pages/assessment/assessment.ts | 15 +++--
.../pages/edit-submission/edit-submission.ts | 29 ++++------
.../workshop/pages/submission/submission.ts | 13 ++---
src/addon/notes/pages/add/add.ts | 7 +--
src/components/local-file/local-file.ts | 7 +--
src/components/search-box/search-box.ts | 9 ++-
.../send-message-form/send-message-form.ts | 9 ++-
src/core/comments/pages/add/add.ts | 7 +--
.../self-enrol-password.ts | 10 ++--
.../rich-text-editor/rich-text-editor.ts | 8 +--
.../login/pages/credentials/credentials.ts | 5 +-
.../login/pages/email-signup/email-signup.ts | 10 +---
.../forgotten-password/forgotten-password.ts | 5 +-
src/core/login/pages/reconnect/reconnect.ts | 5 +-
src/core/login/pages/site/site.ts | 10 +---
src/providers/events.ts | 2 +-
src/providers/utils/dom.ts | 58 ++++++++++++++-----
29 files changed, 190 insertions(+), 215 deletions(-)
diff --git a/src/addon/calendar/pages/edit-event/edit-event.ts b/src/addon/calendar/pages/edit-event/edit-event.ts
index 0296859a5d5..fe80b521b9d 100644
--- a/src/addon/calendar/pages/edit-event/edit-event.ts
+++ b/src/addon/calendar/pages/edit-event/edit-event.ts
@@ -497,10 +497,7 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy {
this.calendarProvider.submitEvent(this.eventId, data).then((result) => {
event = result.event;
- this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
- form: this.formElement.nativeElement,
- online: result.sent,
- }, this.currentSite.getId());
+ this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, result.sent, this.currentSite.getId());
if (result.sent) {
// Event created or edited, invalidate right days & months.
@@ -563,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.
@@ -578,16 +578,18 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy {
*
* @return Resolved if we can leave it, rejected if not.
*/
- ionViewCanLeave(): boolean | Promise {
-
+ async ionViewCanLeave(): Promise {
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);
diff --git a/src/addon/mod/assign/pages/edit-feedback-modal/edit-feedback-modal.ts b/src/addon/mod/assign/pages/edit-feedback-modal/edit-feedback-modal.ts
index 599f8aa8680..5ea771319d9 100644
--- a/src/addon/mod/assign/pages/edit-feedback-modal/edit-feedback-modal.ts
+++ b/src/addon/mod/assign/pages/edit-feedback-modal/edit-feedback-modal.ts
@@ -61,16 +61,17 @@ export class AddonModAssignEditFeedbackModalPage {
*
* @return Resolved if we can leave it, rejected if not.
*/
- ionViewCanLeave(): boolean | Promise {
+ async ionViewCanLeave(): Promise {
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());
}
/**
@@ -91,10 +92,7 @@ export class AddonModAssignEditFeedbackModalPage {
e.preventDefault();
e.stopPropagation();
- this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
- form: this.formElement.nativeElement,
- online: false,
- }, this.sitesProvider.getCurrentSiteId());
+ this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, false, this.sitesProvider.getCurrentSiteId());
// Close the modal, sending the input data.
this.forceLeave = true;
diff --git a/src/addon/mod/assign/pages/edit/edit.ts b/src/addon/mod/assign/pages/edit/edit.ts
index 901cc2baa16..4ec6fe6d2ba 100644
--- a/src/addon/mod/assign/pages/edit/edit.ts
+++ b/src/addon/mod/assign/pages/edit/edit.ts
@@ -85,20 +85,21 @@ export class AddonModAssignEditPage implements OnInit, OnDestroy {
*
* @return Resolved if we can leave it, rejected if not.
*/
- ionViewCanLeave(): boolean | Promise {
+ async ionViewCanLeave(): Promise {
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());
}
/**
@@ -317,10 +318,7 @@ export class AddonModAssignEditPage implements OnInit, OnDestroy {
await this.assignHelper.clearSubmissionPluginTmpData(this.assign, this.userSubmission, inputData);
// Submission saved, trigger events.
- this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
- form: this.formElement.nativeElement,
- online: sent,
- }, this.sitesProvider.getCurrentSiteId());
+ this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, sent, this.sitesProvider.getCurrentSiteId());
const params = {
assignmentId: this.assign.id,
diff --git a/src/addon/mod/data/pages/edit/edit.ts b/src/addon/mod/data/pages/edit/edit.ts
index 6bc8c66ff53..20a58c60c83 100644
--- a/src/addon/mod/data/pages/edit/edit.ts
+++ b/src/addon/mod/data/pages/edit/edit.ts
@@ -96,28 +96,25 @@ export class AddonModDataEditPage {
*
* @return Resolved if we can leave it, rejected if not.
*/
- ionViewCanLeave(): boolean | Promise {
+ async ionViewCanLeave(): Promise {
if (this.forceLeave || !this.entry) {
- return true;
+ return;
}
const inputData = this.editForm.value;
- return this.dataHelper.hasEditDataChanged(inputData, this.fieldsArray, this.data.id,
- this.entry.contents).then((changed) => {
- if (!changed) {
- return Promise.resolve();
- }
+ const changed = await this.dataHelper.hasEditDataChanged(inputData, this.fieldsArray, this.data.id, this.entry.contents);
+ if (changed) {
// 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.
- return this.dataHelper.getEditTmpFiles(inputData, this.fieldsArray, this.data.id,
- this.entry.contents).then((files) => {
- this.fileUploaderProvider.clearTmpFiles(files);
- });
- });
+ await this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit'));
+ }
+
+ // Delete the local files from the tmp folder.
+ const files = await this.dataHelper.getEditTmpFiles(inputData, this.fieldsArray, this.data.id, this.entry.contents);
+ 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.
if ((this.entryId && result.updated) || (!this.entryId && result.newentryid)) {
- this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
- form: this.formElement.nativeElement,
- online: result.sent,
- }, this.siteId);
+ this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, result.sent, this.siteId);
const promises = [];
diff --git a/src/addon/mod/data/pages/search/search.ts b/src/addon/mod/data/pages/search/search.ts
index 5834e6cccda..4d2263630fc 100644
--- a/src/addon/mod/data/pages/search/search.ts
+++ b/src/addon/mod/data/pages/search/search.ts
@@ -186,6 +186,12 @@ export class AddonModDataSearchPage {
* @param data Data to return to the page.
*/
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);
}
@@ -220,11 +226,6 @@ export class AddonModDataSearchPage {
this.search.sortBy = searchedData.sortBy;
this.search.sortDirection = searchedData.sortDirection;
- this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
- form: this.formElement.nativeElement,
- online: false,
- }, this.sitesProvider.getCurrentSiteId());
-
this.closeModal(this.search);
}
}
diff --git a/src/addon/mod/lesson/components/index/index.ts b/src/addon/mod/lesson/components/index/index.ts
index b3b4b95a7cc..23ad87ae647 100644
--- a/src/addon/mod/lesson/components/index/index.ts
+++ b/src/addon/mod/lesson/components/index/index.ts
@@ -14,7 +14,6 @@
import { Component, Optional, Injector, Input, ViewChild, ElementRef } from '@angular/core';
import { Content, NavController } from 'ionic-angular';
-import { CoreEventsProvider } from '@providers/events';
import { CoreGroupsProvider, CoreGroupInfo } from '@providers/groups';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreUtilsProvider } from '@providers/utils/utils';
@@ -587,10 +586,7 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo
this.refreshIcon = 'refresh';
this.syncIcon = 'sync';
- this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
- form: this.formElement.nativeElement,
- online: true,
- }, this.siteId);
+ this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, true, this.siteId);
});
}
diff --git a/src/addon/mod/lesson/pages/password-modal/password-modal.ts b/src/addon/mod/lesson/pages/password-modal/password-modal.ts
index d72df1ca4d9..2446bb2660c 100644
--- a/src/addon/mod/lesson/pages/password-modal/password-modal.ts
+++ b/src/addon/mod/lesson/pages/password-modal/password-modal.ts
@@ -16,6 +16,7 @@ import { Component, ViewChild, ElementRef } from '@angular/core';
import { IonicPage, ViewController } from 'ionic-angular';
import { CoreEventsProvider } from '@providers/events';
import { CoreSitesProvider } from '@providers/sites';
+import { CoreDomUtilsProvider } from '@providers/utils/dom';
/**
* Modal that asks the password for a lesson.
@@ -30,7 +31,8 @@ export class AddonModLessonPasswordModalPage {
constructor(protected viewCtrl: ViewController,
protected eventsProvider: CoreEventsProvider,
- protected sitesProvider: CoreSitesProvider) { }
+ protected sitesProvider: CoreSitesProvider,
+ protected domUtils: CoreDomUtilsProvider) { }
/**
* Send the password back.
@@ -42,10 +44,7 @@ export class AddonModLessonPasswordModalPage {
e.preventDefault();
e.stopPropagation();
- this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
- form: this.formElement.nativeElement,
- online: false,
- }, this.sitesProvider.getCurrentSiteId());
+ this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, false, this.sitesProvider.getCurrentSiteId());
this.viewCtrl.dismiss(password.value);
}
@@ -54,6 +53,8 @@ export class AddonModLessonPasswordModalPage {
* Close modal.
*/
closeModal(): void {
+ this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.sitesProvider.getCurrentSiteId());
+
this.viewCtrl.dismiss();
}
}
diff --git a/src/addon/mod/lesson/pages/player/player.ts b/src/addon/mod/lesson/pages/player/player.ts
index 7ab23e96f29..44d2a87cabf 100644
--- a/src/addon/mod/lesson/pages/player/player.ts
+++ b/src/addon/mod/lesson/pages/player/player.ts
@@ -137,19 +137,19 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy {
*
* @return Resolved if we can leave it, rejected if not.
*/
- ionViewCanLeave(): boolean | Promise {
+ async ionViewCanLeave(): Promise {
if (this.forceLeave) {
- return true;
+ return;
}
if (this.question && !this.eolData && !this.processData && this.originalData) {
// Question shown. Check if there is any change.
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) => {
if (formSubmitted) {
- this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
- form: this.formElement.nativeElement,
- online: result.sent,
- }, this.sitesProvider.getCurrentSiteId());
+ this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, result.sent,
+ this.sitesProvider.getCurrentSiteId());
}
if (!this.offline && !this.review && this.lessonProvider.isLessonOffline(this.lesson)) {
diff --git a/src/addon/mod/quiz/pages/player/player.ts b/src/addon/mod/quiz/pages/player/player.ts
index 31acddaa46c..92d9a04ac8a 100644
--- a/src/addon/mod/quiz/pages/player/player.ts
+++ b/src/addon/mod/quiz/pages/player/player.ts
@@ -137,26 +137,28 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy {
*
* @return Resolved if we can leave it, rejected if not.
*/
- ionViewCanLeave(): boolean | Promise {
+ async ionViewCanLeave(): Promise {
if (this.forceLeave) {
- return true;
+ return;
}
if (this.questions && this.questions.length && !this.showSummary) {
// Save answers.
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.
modal.dismiss();
- return this.domUtils.showConfirm(this.translate.instant('addon.mod_quiz.confirmleavequizonerror'));
- }).finally(() => {
+ await this.domUtils.showConfirm(this.translate.instant('addon.mod_quiz.confirmleavequizonerror'));
+
+ this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.sitesProvider.getCurrentSiteId());
+ } finally {
modal.dismiss();
- });
+ }
}
-
- return Promise.resolve();
}
/**
@@ -587,10 +589,8 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy {
this.autoSave.cancelAutoSave();
this.autoSave.hideAutoSaveError();
- this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
- form: this.formElement.nativeElement,
- online: !this.offline,
- }, this.sitesProvider.getCurrentSiteId());
+ this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, !this.offline,
+ this.sitesProvider.getCurrentSiteId());
});
}
diff --git a/src/addon/mod/quiz/pages/preflight-modal/preflight-modal.ts b/src/addon/mod/quiz/pages/preflight-modal/preflight-modal.ts
index 28681c8a5ca..fa149c30fd4 100644
--- a/src/addon/mod/quiz/pages/preflight-modal/preflight-modal.ts
+++ b/src/addon/mod/quiz/pages/preflight-modal/preflight-modal.ts
@@ -120,10 +120,7 @@ export class AddonModQuizPreflightModalPage implements OnInit {
this.domUtils.showErrorModal('core.errorinvalidform', true);
}
} else {
- this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
- form: this.formElement.nativeElement,
- online: false,
- }, this.siteId);
+ this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, false, this.siteId);
this.viewCtrl.dismiss(this.preflightForm.value);
}
@@ -133,6 +130,8 @@ export class AddonModQuizPreflightModalPage implements OnInit {
* Close modal.
*/
closeModal(): void {
+ this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.siteId);
+
this.viewCtrl.dismiss();
}
}
diff --git a/src/addon/mod/wiki/pages/edit/edit.ts b/src/addon/mod/wiki/pages/edit/edit.ts
index 7df9ad26ae7..7cd65dccbfe 100644
--- a/src/addon/mod/wiki/pages/edit/edit.ts
+++ b/src/addon/mod/wiki/pages/edit/edit.ts
@@ -346,17 +346,17 @@ export class AddonModWikiEditPage implements OnInit, OnDestroy {
*
* @return Resolved if we can leave it, rejected if not.
*/
- ionViewCanLeave(): boolean | Promise {
+ async ionViewCanLeave(): Promise {
if (this.forceLeave) {
- return true;
+ return;
}
// Check if data has changed.
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.
promise = this.wikiProvider.editPage(this.pageId, text, this.section).then(() => {
- this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
- form: this.formElement.nativeElement,
- online: true,
- }, this.sitesProvider.getCurrentSiteId());
+ this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, true,
+ this.sitesProvider.getCurrentSiteId());
// Invalidate page since it changed.
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) => {
- this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
- form: this.formElement.nativeElement,
- online: id > 0,
- }, this.sitesProvider.getCurrentSiteId());
+ this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, id > 0,
+ this.sitesProvider.getCurrentSiteId());
if (id > 0) {
// Page was created, get its data and go to the page.
diff --git a/src/addon/mod/workshop/components/assessment-strategy/assessment-strategy.ts b/src/addon/mod/workshop/components/assessment-strategy/assessment-strategy.ts
index 9b239ddacbe..a0121dee660 100644
--- a/src/addon/mod/workshop/components/assessment-strategy/assessment-strategy.ts
+++ b/src/addon/mod/workshop/components/assessment-strategy/assessment-strategy.ts
@@ -304,10 +304,7 @@ export class AddonModWorkshopAssessmentStrategyComponent implements OnInit {
assessmentData, false, allowOffline);
}).then((grade) => {
- this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
- form: this.formElement.nativeElement,
- online: !!grade,
- }, this.sitesProvider.getCurrentSiteId());
+ this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, !!grade, this.sitesProvider.getCurrentSiteId());
const promises = [];
diff --git a/src/addon/mod/workshop/pages/assessment/assessment.ts b/src/addon/mod/workshop/pages/assessment/assessment.ts
index ae9a53d6225..09be157c7fb 100644
--- a/src/addon/mod/workshop/pages/assessment/assessment.ts
+++ b/src/addon/mod/workshop/pages/assessment/assessment.ts
@@ -120,17 +120,19 @@ export class AddonModWorkshopAssessmentPage implements OnInit, OnDestroy {
*
* @return Resolved if we can leave it, rejected if not.
*/
- ionViewCanLeave(): boolean | Promise {
+ async ionViewCanLeave(): Promise {
if (this.forceLeave || !this.evaluating) {
- return true;
+ return;
}
if (!this.hasEvaluationChanged()) {
- return Promise.resolve();
+ return;
}
// 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,
inputData.weight, inputData.grade).then((result) => {
- this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
- form: this.formElement.nativeElement,
- online: !!result,
- }, this.siteId);
+ this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, !!result, this.siteId);
const data = {
workshopId: this.workshopId,
diff --git a/src/addon/mod/workshop/pages/edit-submission/edit-submission.ts b/src/addon/mod/workshop/pages/edit-submission/edit-submission.ts
index 121d11ed8fb..0911dc7d04a 100644
--- a/src/addon/mod/workshop/pages/edit-submission/edit-submission.ts
+++ b/src/addon/mod/workshop/pages/edit-submission/edit-submission.ts
@@ -112,27 +112,23 @@ export class AddonModWorkshopEditSubmissionPage implements OnInit, OnDestroy {
*
* @return Resolved if we can leave it, rejected if not.
*/
- ionViewCanLeave(): boolean | Promise {
+ async ionViewCanLeave(): Promise {
if (this.forceLeave) {
- return true;
+ return;
}
- let promise;
-
// Check if data has changed.
- if (!this.hasDataChanged()) {
- promise = Promise.resolve();
- } else {
+ if (this.hasDataChanged()) {
// 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) {
- // Delete the local files from the tmp folder.
- this.fileUploaderProvider.clearTmpFiles(this.submission.attachmentfiles);
- }
- });
+ if (this.submission.attachmentfiles) {
+ // Delete the local files from the tmp folder.
+ 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);
}).then((newSubmissionId) => {
- this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
- form: this.formElement.nativeElement,
- online: !!newSubmissionId,
- }, this.siteId);
+ this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, !!newSubmissionId, this.siteId);
const data = {
workshopId: this.workshopId,
diff --git a/src/addon/mod/workshop/pages/submission/submission.ts b/src/addon/mod/workshop/pages/submission/submission.ts
index a1c3b6d501b..947aec803fb 100644
--- a/src/addon/mod/workshop/pages/submission/submission.ts
+++ b/src/addon/mod/workshop/pages/submission/submission.ts
@@ -144,14 +144,16 @@ export class AddonModWorkshopSubmissionPage implements OnInit, OnDestroy {
*
* @return Resolved if we can leave it, rejected if not.
*/
- ionViewCanLeave(): boolean | Promise {
+ async ionViewCanLeave(): Promise {
const assessmentHasChanged = this.assessmentStrategy && this.assessmentStrategy.hasDataChanged();
if (this.forceLeave || (!this.hasEvaluationChanged() && !assessmentHasChanged)) {
- return true;
+ return;
}
// 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,
inputData.published, inputData.grade).then((result) => {
- this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
- form: this.formElement.nativeElement,
- online: !!result,
- }, this.siteId);
+ this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, !!result, this.siteId);
const data = {
workshopId: this.workshopId,
diff --git a/src/addon/notes/pages/add/add.ts b/src/addon/notes/pages/add/add.ts
index d00e95aa201..64459dd0a6f 100644
--- a/src/addon/notes/pages/add/add.ts
+++ b/src/addon/notes/pages/add/add.ts
@@ -65,10 +65,7 @@ export class AddonNotesAddPage {
this.processing = true;
this.notesProvider.addNote(this.userId, this.courseId, this.type, this.text).then((sent) => {
- this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
- form: this.formElement.nativeElement,
- online: sent,
- }, this.sitesProvider.getCurrentSiteId());
+ this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, sent, this.sitesProvider.getCurrentSiteId());
this.viewCtrl.dismiss({type: this.type, sent: true}).finally(() => {
this.domUtils.showToast(sent ? 'addon.notes.eventnotecreated' : 'core.datastoredoffline', true, 3000);
@@ -85,6 +82,8 @@ export class AddonNotesAddPage {
* Close modal.
*/
closeModal(): void {
+ this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.sitesProvider.getCurrentSiteId());
+
this.viewCtrl.dismiss({type: this.type});
}
}
diff --git a/src/components/local-file/local-file.ts b/src/components/local-file/local-file.ts
index 31fd41bf08e..d430af3f4bf 100644
--- a/src/components/local-file/local-file.ts
+++ b/src/components/local-file/local-file.ts
@@ -143,6 +143,7 @@ export class CoreLocalFileComponent implements OnInit {
if (newName == this.file.name) {
// Name hasn't changed, stop.
this.editMode = false;
+ this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.sitesProvider.getCurrentSiteId());
return;
}
@@ -159,10 +160,8 @@ export class CoreLocalFileComponent implements OnInit {
// File doesn't exist, move it.
return this.fileProvider.moveFile(this.relativePath, newPath).then((fileEntry) => {
- this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
- form: this.formElement.nativeElement,
- online: false,
- }, this.sitesProvider.getCurrentSiteId());
+ this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, false,
+ this.sitesProvider.getCurrentSiteId());
this.editMode = false;
this.file = fileEntry;
diff --git a/src/components/search-box/search-box.ts b/src/components/search-box/search-box.ts
index 4698e4584a1..8d313b71be6 100644
--- a/src/components/search-box/search-box.ts
+++ b/src/components/search-box/search-box.ts
@@ -16,6 +16,7 @@ import { Component, Input, Output, EventEmitter, OnInit, ViewChild, ElementRef }
import { TranslateService } from '@ngx-translate/core';
import { CoreEventsProvider } from '@providers/events';
import { CoreSitesProvider } from '@providers/sites';
+import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreUtilsProvider } from '@providers/utils/utils';
/**
@@ -53,7 +54,8 @@ export class CoreSearchBoxComponent implements OnInit {
constructor(protected translate: TranslateService,
protected utils: CoreUtilsProvider,
protected eventsProvider: CoreEventsProvider,
- protected sitesProvider: CoreSitesProvider) {
+ protected sitesProvider: CoreSitesProvider,
+ protected domUtils: CoreDomUtilsProvider) {
this.onSubmit = new EventEmitter();
this.onClear = new EventEmitter();
}
@@ -80,10 +82,7 @@ export class CoreSearchBoxComponent implements OnInit {
return;
}
- this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
- form: this.formElement.nativeElement,
- online: false,
- }, this.sitesProvider.getCurrentSiteId());
+ this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, false, this.sitesProvider.getCurrentSiteId());
this.searched = true;
this.onSubmit.emit(this.searchText);
diff --git a/src/components/send-message-form/send-message-form.ts b/src/components/send-message-form/send-message-form.ts
index 147118f7c8f..05a3de17f3f 100644
--- a/src/components/send-message-form/send-message-form.ts
+++ b/src/components/send-message-form/send-message-form.ts
@@ -19,6 +19,7 @@ import { CoreEventsProvider } from '@providers/events';
import { CoreSitesProvider } from '@providers/sites';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreTextUtilsProvider } from '@providers/utils/text';
+import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreConstants } from '@core/constants';
/**
@@ -52,7 +53,8 @@ export class CoreSendMessageFormComponent implements OnInit {
configProvider: CoreConfigProvider,
protected eventsProvider: CoreEventsProvider,
protected sitesProvider: CoreSitesProvider,
- protected appProvider: CoreAppProvider) {
+ protected appProvider: CoreAppProvider,
+ protected domUtils: CoreDomUtilsProvider) {
this.onSubmit = new EventEmitter();
this.onResize = new EventEmitter();
@@ -88,10 +90,7 @@ export class CoreSendMessageFormComponent implements OnInit {
this.message = ''; // Reset the form.
- this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
- form: this.formElement.nativeElement,
- online: false,
- }, this.sitesProvider.getCurrentSiteId());
+ this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, false, this.sitesProvider.getCurrentSiteId());
value = this.textUtils.replaceNewLines(value, ' ');
this.onSubmit.emit(value);
diff --git a/src/core/comments/pages/add/add.ts b/src/core/comments/pages/add/add.ts
index 583cb0300dd..826d642fcf0 100644
--- a/src/core/comments/pages/add/add.ts
+++ b/src/core/comments/pages/add/add.ts
@@ -71,10 +71,8 @@ export class CoreCommentsAddPage {
this.commentsProvider.addComment(this.content, this.contextLevel, this.instanceId, this.componentName, this.itemId,
this.area).then((commentsResponse) => {
- this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
- form: this.formElement.nativeElement,
- online: !!commentsResponse,
- }, this.sitesProvider.getCurrentSiteId());
+ this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, !!commentsResponse,
+ this.sitesProvider.getCurrentSiteId());
this.viewCtrl.dismiss({comments: commentsResponse}).finally(() => {
this.domUtils.showToast(commentsResponse ? 'core.comments.eventcommentcreated' : 'core.datastoredoffline', true,
@@ -92,6 +90,7 @@ export class CoreCommentsAddPage {
* Close modal.
*/
closeModal(): void {
+ this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.sitesProvider.getCurrentSiteId());
this.viewCtrl.dismiss();
}
}
diff --git a/src/core/courses/pages/self-enrol-password/self-enrol-password.ts b/src/core/courses/pages/self-enrol-password/self-enrol-password.ts
index c95c5ec83b6..7e0080248d7 100644
--- a/src/core/courses/pages/self-enrol-password/self-enrol-password.ts
+++ b/src/core/courses/pages/self-enrol-password/self-enrol-password.ts
@@ -16,6 +16,7 @@ import { Component, ViewChild, ElementRef } from '@angular/core';
import { IonicPage, ViewController } from 'ionic-angular';
import { CoreEventsProvider } from '@providers/events';
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.
@@ -31,12 +32,14 @@ export class CoreCoursesSelfEnrolPasswordPage {
constructor(protected viewCtrl: ViewController,
protected eventsProvider: CoreEventsProvider,
- protected sitesProvider: CoreSitesProvider) { }
+ protected sitesProvider: CoreSitesProvider,
+ protected domUtils: CoreDomUtilsProvider) { }
/**
* Close help modal.
*/
close(): void {
+ this.domUtils.triggerFormCancelledEvent(this.formElement.nativeElement, this.sitesProvider.getCurrentSiteId());
this.viewCtrl.dismiss();
}
@@ -50,10 +53,7 @@ export class CoreCoursesSelfEnrolPasswordPage {
e.preventDefault();
e.stopPropagation();
- this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
- form: this.formElement.nativeElement,
- online: false,
- }, this.sitesProvider.getCurrentSiteId());
+ this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, false, this.sitesProvider.getCurrentSiteId());
this.viewCtrl.dismiss(password);
}
diff --git a/src/core/editor/components/rich-text-editor/rich-text-editor.ts b/src/core/editor/components/rich-text-editor/rich-text-editor.ts
index 2fa0bc6131f..b28969ebe0c 100644
--- a/src/core/editor/components/rich-text-editor/rich-text-editor.ts
+++ b/src/core/editor/components/rich-text-editor/rich-text-editor.ts
@@ -194,7 +194,7 @@ export class CoreEditorRichTextEditorComponent implements AfterContentInit, OnDe
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');
if (data.form && form && data.form == form) {
diff --git a/src/core/login/pages/credentials/credentials.ts b/src/core/login/pages/credentials/credentials.ts
index 3d3f6f5e4d8..0aaccaa1220 100644
--- a/src/core/login/pages/credentials/credentials.ts
+++ b/src/core/login/pages/credentials/credentials.ts
@@ -246,10 +246,7 @@ export class CoreLoginCredentialsPage {
}).finally(() => {
modal.dismiss();
- this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
- form: this.formElement.nativeElement,
- online: true,
- });
+ this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, true);
});
}
diff --git a/src/core/login/pages/email-signup/email-signup.ts b/src/core/login/pages/email-signup/email-signup.ts
index e9563da5928..f4cc0899666 100644
--- a/src/core/login/pages/email-signup/email-signup.ts
+++ b/src/core/login/pages/email-signup/email-signup.ts
@@ -277,10 +277,7 @@ export class CoreLoginEmailSignupPage {
}).then((result) => {
if (result.success) {
- this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
- form: this.signupFormElement.nativeElement,
- online: true,
- });
+ this.domUtils.triggerFormSubmittedEvent(this.signupFormElement.nativeElement, true);
// Show alert and ho back.
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.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
- form: this.ageFormElement.nativeElement,
- online: true,
- });
+ this.domUtils.triggerFormSubmittedEvent(this.ageFormElement.nativeElement, true);
if (!result.status) {
if (this.countryControl.value) {
diff --git a/src/core/login/pages/forgotten-password/forgotten-password.ts b/src/core/login/pages/forgotten-password/forgotten-password.ts
index 1187d903ac2..9b975e958c3 100644
--- a/src/core/login/pages/forgotten-password/forgotten-password.ts
+++ b/src/core/login/pages/forgotten-password/forgotten-password.ts
@@ -82,10 +82,7 @@ export class CoreLoginForgottenPasswordPage {
this.domUtils.showErrorModal(response.notice);
} else {
// Success.
- this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
- form: this.formElement.nativeElement,
- online: true,
- });
+ this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, true);
this.domUtils.showAlert(this.translate.instant('core.success'), response.notice);
this.navCtrl.pop();
diff --git a/src/core/login/pages/reconnect/reconnect.ts b/src/core/login/pages/reconnect/reconnect.ts
index 73b5515748b..59918eab7ba 100644
--- a/src/core/login/pages/reconnect/reconnect.ts
+++ b/src/core/login/pages/reconnect/reconnect.ts
@@ -181,10 +181,7 @@ export class CoreLoginReconnectPage {
this.sitesProvider.getUserToken(siteUrl, username, password).then((data) => {
return this.sitesProvider.updateSiteToken(this.infoSiteUrl, username, data.token, data.privateToken).then(() => {
- this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
- form: this.formElement.nativeElement,
- online: true,
- });
+ this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, true);
// Update site info too because functions might have changed (e.g. unisntall local_mobile).
return this.sitesProvider.updateSiteInfoByUrl(this.infoSiteUrl, username).then(() => {
diff --git a/src/core/login/pages/site/site.ts b/src/core/login/pages/site/site.ts
index d20b510f774..92193fd920c 100644
--- a/src/core/login/pages/site/site.ts
+++ b/src/core/login/pages/site/site.ts
@@ -107,10 +107,7 @@ export class CoreLoginSitePage {
this.sitesProvider.getUserToken(siteData.url, siteData.username, siteData.password).then((data) => {
return this.sitesProvider.newSite(data.siteUrl, data.token, data.privateToken).then(() => {
- this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
- form: this.formElement.nativeElement,
- online: true,
- });
+ this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, true);
return this.loginHelper.goToSiteInitialPage();
}, (error) => {
@@ -192,10 +189,7 @@ export class CoreLoginSitePage {
protected async login(response: CoreSiteCheckResponse): Promise {
return this.sitesProvider.checkRequiredMinimumVersion(response.config).then(() => {
- this.eventsProvider.trigger(CoreEventsProvider.FORM_SUBMITTED, {
- form: this.formElement.nativeElement,
- online: true,
- });
+ this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, true);
if (response.warning) {
this.domUtils.showErrorModal(response.warning, true, 4000);
diff --git a/src/providers/events.ts b/src/providers/events.ts
index d20103e8816..abed87a95d3 100644
--- a/src/providers/events.ts
+++ b/src/providers/events.ts
@@ -64,7 +64,7 @@ export class CoreEventsProvider {
static SELECT_COURSE_TAB = 'select_course_tab';
static WS_CACHE_INVALIDATED = 'ws_cache_invalidated';
static SITE_STORAGE_DELETED = 'site_storage_deleted';
- static FORM_SUBMITTED = 'form_submitted';
+ static FORM_ACTION = 'form_action';
protected logger;
protected observables: { [s: string]: Subject } = {};
diff --git a/src/providers/utils/dom.ts b/src/providers/utils/dom.ts
index 91e4b7ad1bb..748e7392316 100644
--- a/src/providers/utils/dom.ts
+++ b/src/providers/utils/dom.ts
@@ -22,6 +22,7 @@ import { TranslateService } from '@ngx-translate/core';
import { CoreTextUtilsProvider } from './text';
import { CoreAppProvider } from '../app';
import { CoreConfigProvider } from '../config';
+import { CoreEventsProvider } from '../events';
import { CoreLoggerProvider } from '../logger';
import { CoreUrlUtilsProvider } from './url';
import { CoreFileProvider } from '@providers/file';
@@ -64,20 +65,21 @@ export class CoreDomUtilsProvider {
protected displayedAlerts = {}; // To prevent duplicated alerts.
protected logger;
- constructor(private translate: TranslateService,
- private loadingCtrl: LoadingController,
- private toastCtrl: ToastController,
- private alertCtrl: AlertController,
- private textUtils: CoreTextUtilsProvider,
- private appProvider: CoreAppProvider,
- private platform: Platform,
- private configProvider: CoreConfigProvider,
- private urlUtils: CoreUrlUtilsProvider,
- private modalCtrl: ModalController,
- private sanitizer: DomSanitizer,
- private popoverCtrl: PopoverController,
- private fileProvider: CoreFileProvider,
- loggerProvider: CoreLoggerProvider) {
+ constructor(protected translate: TranslateService,
+ protected loadingCtrl: LoadingController,
+ protected toastCtrl: ToastController,
+ protected alertCtrl: AlertController,
+ protected textUtils: CoreTextUtilsProvider,
+ protected appProvider: CoreAppProvider,
+ protected platform: Platform,
+ protected configProvider: CoreConfigProvider,
+ protected urlUtils: CoreUrlUtilsProvider,
+ protected modalCtrl: ModalController,
+ protected sanitizer: DomSanitizer,
+ protected popoverCtrl: PopoverController,
+ protected fileProvider: CoreFileProvider,
+ loggerProvider: CoreLoggerProvider,
+ protected eventsProvider: CoreEventsProvider) {
this.logger = loggerProvider.getInstance('CoreDomUtilsProvider');
@@ -1625,4 +1627,32 @@ export class CoreDomUtilsProvider {
// Now move the element into the wrapper.
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);
+ }
}
From 70cdf8fc9c24de3a04a51622e636237f11b4ee26 Mon Sep 17 00:00:00 2001
From: Dani Palou
Date: Tue, 18 Feb 2020 11:38:04 +0100
Subject: [PATCH 8/9] MOBILE-3323 search: Delete old search component created
by rebase
---
src/components/search-box/search-box.ts | 99 -------------------------
1 file changed, 99 deletions(-)
delete mode 100644 src/components/search-box/search-box.ts
diff --git a/src/components/search-box/search-box.ts b/src/components/search-box/search-box.ts
deleted file mode 100644
index 8d313b71be6..00000000000
--- a/src/components/search-box/search-box.ts
+++ /dev/null
@@ -1,99 +0,0 @@
-// (C) Copyright 2015 Moodle Pty Ltd.
-//
-// 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, Output, EventEmitter, OnInit, ViewChild, ElementRef } from '@angular/core';
-import { TranslateService } from '@ngx-translate/core';
-import { CoreEventsProvider } from '@providers/events';
-import { CoreSitesProvider } from '@providers/sites';
-import { CoreDomUtilsProvider } from '@providers/utils/dom';
-import { CoreUtilsProvider } from '@providers/utils/utils';
-
-/**
- * Component to display a "search box".
- *
- * @description
- * This component will display a standalone search box with its search button in order to have a better UX.
- *
- * Example usage:
- *
- */
-@Component({
- selector: 'core-search-box',
- templateUrl: 'core-search-box.html'
-})
-export class CoreSearchBoxComponent implements OnInit {
- @Input() searchLabel?: string; // Label to be used on action button.
- @Input() placeholder?: string; // Placeholder text for search text input.
- @Input() autocorrect = 'on'; // Enables/disable Autocorrection on search text input.
- @Input() spellcheck?: string | boolean = true; // Enables/disable Spellchecker on search text input.
- @Input() autoFocus?: string | boolean; // Enables/disable Autofocus when entering view.
- @Input() lengthCheck = 3; // Check value length before submit. If 0, any string will be submitted.
- @Input() showClear = true; // Show/hide clear button.
- @Input() disabled = false; // Disables the input text.
- @Input() initialSearch: string; // Initial search text.
- @Output() onSubmit: EventEmitter; // Send data when submitting the search form.
- @Output() onClear: EventEmitter; // Send event when clearing the search form.
-
- @ViewChild('searchForm') formElement: ElementRef;
-
- searched = false;
- searchText = '';
-
- constructor(protected translate: TranslateService,
- protected utils: CoreUtilsProvider,
- protected eventsProvider: CoreEventsProvider,
- protected sitesProvider: CoreSitesProvider,
- protected domUtils: CoreDomUtilsProvider) {
- this.onSubmit = new EventEmitter();
- this.onClear = new EventEmitter();
- }
-
- ngOnInit(): void {
- this.searchLabel = this.searchLabel || this.translate.instant('core.search');
- this.placeholder = this.placeholder || this.translate.instant('core.search');
- this.spellcheck = this.utils.isTrueOrOne(this.spellcheck);
- this.showClear = this.utils.isTrueOrOne(this.showClear);
- this.searchText = this.initialSearch || '';
- }
-
- /**
- * Form submitted.
- *
- * @param e Event.
- */
- submitForm(e: Event): void {
- e.preventDefault();
- e.stopPropagation();
-
- if (this.searchText.length < this.lengthCheck) {
- // The view should handle this case, but we check it here too just in case.
- return;
- }
-
- this.domUtils.triggerFormSubmittedEvent(this.formElement.nativeElement, false, this.sitesProvider.getCurrentSiteId());
-
- this.searched = true;
- this.onSubmit.emit(this.searchText);
- }
-
- /**
- * Form submitted.
- */
- clearForm(): void {
- this.searched = false;
- this.searchText = '';
- this.onClear.emit();
- }
-}
From 7d026fd413573d76e1c07dea61fe0fb979361a7c Mon Sep 17 00:00:00 2001
From: Dani Palou
Date: Tue, 18 Feb 2020 11:47:30 +0100
Subject: [PATCH 9/9] MOBILE-3323 search: Fix error cannot read length of
undefined
---
src/core/search/components/search-box/search-box.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/core/search/components/search-box/search-box.ts b/src/core/search/components/search-box/search-box.ts
index 1f1ec4d915b..5295790c5bb 100644
--- a/src/core/search/components/search-box/search-box.ts
+++ b/src/core/search/components/search-box/search-box.ts
@@ -54,7 +54,7 @@ export class CoreSearchBoxComponent implements OnInit, OnDestroy {
searched = ''; // Last search emitted.
searchText = '';
- history: CoreSearchHistoryItem[];
+ history: CoreSearchHistoryItem[] = [];
historyShown = false;
protected elementClicked = '';