diff --git a/src/addons/mod/forum/components/components.module.ts b/src/addons/mod/forum/components/components.module.ts
index 7ba512416..885c436d7 100644
--- a/src/addons/mod/forum/components/components.module.ts
+++ b/src/addons/mod/forum/components/components.module.ts
@@ -19,17 +19,19 @@ import { CoreEditorComponentsModule } from '@features/editor/components/componen
import { CoreSharedModule } from '@/core/shared.module';
import { CoreTagComponentsModule } from '@features/tag/components/components.module';
+import { AddonModForumDiscussionOptionsMenuComponent } from './discussion-options-menu/discussion-options-menu';
+import { AddonModForumEditPostComponent } from './edit-post/edit-post';
import { AddonModForumIndexComponent } from './index/index';
import { AddonModForumPostComponent } from './post/post';
import { AddonModForumPostOptionsMenuComponent } from './post-options-menu/post-options-menu';
-import { AddonModForumDiscussionOptionsMenuComponent } from './discussion-options-menu/discussion-options-menu';
@NgModule({
declarations: [
+ AddonModForumDiscussionOptionsMenuComponent,
+ AddonModForumEditPostComponent,
AddonModForumIndexComponent,
AddonModForumPostComponent,
AddonModForumPostOptionsMenuComponent,
- AddonModForumDiscussionOptionsMenuComponent,
],
imports: [
CoreSharedModule,
diff --git a/src/addons/mod/forum/components/edit-post/edit-post.html b/src/addons/mod/forum/components/edit-post/edit-post.html
new file mode 100644
index 000000000..ab09104f8
--- /dev/null
+++ b/src/addons/mod/forum/components/edit-post/edit-post.html
@@ -0,0 +1,43 @@
+
+
+
+
+
+ {{ 'addon.mod_forum.yourreply' | translate }}
+
+
+
+
+
+
+
+
+
+
diff --git a/src/addons/mod/forum/components/edit-post/edit-post.ts b/src/addons/mod/forum/components/edit-post/edit-post.ts
new file mode 100644
index 000000000..2704ffa95
--- /dev/null
+++ b/src/addons/mod/forum/components/edit-post/edit-post.ts
@@ -0,0 +1,148 @@
+// (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, ViewChild, ElementRef, Input, OnInit } from '@angular/core';
+import { FormControl } from '@angular/forms';
+import { CoreFileEntry, CoreFileUploader } from '@features/fileuploader/services/fileuploader';
+import { CoreSites } from '@services/sites';
+import { CoreDomUtils } from '@services/utils/dom';
+import { ModalController, Translate } from '@singletons';
+import { AddonModForumData, AddonModForumPost, AddonModForumReply } from '@addons/mod/forum/services/forum.service';
+import { AddonModForumHelper } from '@addons/mod/forum/services/helper.service';
+
+/**
+ * Page that displays a form to edit discussion post.
+ */
+@Component({
+ selector: 'addon-mod-forum-edit-post',
+ templateUrl: 'edit-post.html',
+})
+export class AddonModForumEditPostComponent implements OnInit {
+
+ @ViewChild('editFormEl') formElement!: ElementRef;
+
+ @Input() component!: string; // Component this post belong to.
+ @Input() componentId!: number; // Component ID.
+ @Input() forum!: AddonModForumData; // The forum the post belongs to. Required for attachments and offline posts.
+ @Input() post!: AddonModForumPost;
+
+ messageControl = new FormControl();
+ advanced = false; // Display all form fields.
+ replyData!: AddonModForumReply;
+ originalData!: Omit; // Object with the original post data. Usually shared between posts.
+
+ protected forceLeave = false; // To allow leaving the page without checking for changes.
+
+ ngOnInit(): void {
+ // @todo Override android back button to show confirmation before dismiss.
+
+ this.replyData = {
+ id: this.post.id,
+ subject: this.post.subject,
+ message: this.post.message,
+ files: this.post.attachments || [],
+ };
+
+ // Delete the local files from the tmp folder if any.
+ CoreFileUploader.instance.clearTmpFiles(this.replyData.files as CoreFileEntry[]);
+
+ // Update rich text editor.
+ this.messageControl.setValue(this.replyData.message);
+
+ // Update original data.
+ this.originalData = {
+ subject: this.replyData.subject,
+ message: this.replyData.message,
+ files: this.replyData.files.slice(),
+ };
+
+ // Show advanced fields if any of them has not the default value.
+ this.advanced = this.replyData.files.length > 0;
+ }
+
+ /**
+ * Message changed.
+ *
+ * @param text The new text.
+ */
+ onMessageChange(text: string): void {
+ this.replyData.message = text;
+ }
+
+ /**
+ * Close modal.
+ *
+ * @param data Data to return to the page.
+ */
+ async closeModal(data?: AddonModForumReply): Promise {
+ const confirmDismiss = await this.confirmDismiss();
+
+ if (!confirmDismiss) {
+ return;
+ }
+
+ if (data) {
+ CoreDomUtils.instance.triggerFormSubmittedEvent(this.formElement, false, CoreSites.instance.getCurrentSiteId());
+ } else {
+ CoreDomUtils.instance.triggerFormCancelledEvent(this.formElement, CoreSites.instance.getCurrentSiteId());
+ }
+
+ ModalController.instance.dismiss(data);
+ }
+
+ /**
+ * Reply to this post.
+ *
+ * @param e Click event.
+ */
+ reply(e: Event): void {
+ e.preventDefault();
+ e.stopPropagation();
+
+ // Close the modal, sending the input data.
+ this.forceLeave = true;
+ this.closeModal(this.replyData);
+ }
+
+ /**
+ * Show or hide advanced form fields.
+ */
+ toggleAdvanced(): void {
+ this.advanced = !this.advanced;
+ }
+
+ /**
+ * Check if we can leave the page or not.
+ *
+ * @return Resolved if we can leave it, rejected if not.
+ */
+ private async confirmDismiss(): Promise {
+ if (this.forceLeave || !AddonModForumHelper.instance.hasPostDataChanged(this.replyData, this.originalData)) {
+ return true;
+ }
+
+ try {
+ // Show confirmation if some data has been modified.
+ await CoreDomUtils.instance.showConfirm(Translate.instant('core.confirmcanceledit'));
+
+ // Delete the local files from the tmp folder.
+ CoreFileUploader.instance.clearTmpFiles(this.replyData.files as CoreFileEntry[]);
+
+ return true;
+ } catch (error) {
+ return false;
+ }
+ }
+
+}
diff --git a/src/addons/mod/forum/components/post/post.ts b/src/addons/mod/forum/components/post/post.ts
index f6a20e889..0eaf6f52d 100644
--- a/src/addons/mod/forum/components/post/post.ts
+++ b/src/addons/mod/forum/components/post/post.ts
@@ -36,10 +36,13 @@ import {
AddonModForumDiscussion,
AddonModForumPost,
AddonModForumProvider,
+ AddonModForumReply,
+ AddonModForumUpdateDiscussionPostWSOptionsObject,
+ AddonModForumWSPostAttachment,
} from '../../services/forum.service';
import { CoreTag } from '@features/tag/services/tag';
-import { PopoverController, Translate } from '@singletons';
-import { CoreFileUploader } from '@features/fileuploader/services/fileuploader';
+import { ModalController, PopoverController, Translate } from '@singletons';
+import { CoreFileEntry, CoreFileUploader } from '@features/fileuploader/services/fileuploader';
import { IonContent } from '@ionic/angular';
import { AddonModForumSync } from '../../services/sync.service';
import { CoreSync } from '@services/sync';
@@ -48,6 +51,7 @@ import { AddonModForumHelper } from '../../services/helper.service';
import { AddonModForumOffline, AddonModForumReplyOptions } from '../../services/offline.service';
import { CoreUtils } from '@services/utils/utils';
import { AddonModForumPostOptionsMenuComponent } from '../post-options-menu/post-options-menu';
+import { AddonModForumEditPostComponent } from '../edit-post/edit-post';
/**
* Components that shows a discussion post, its attachments and the action buttons allowed (reply, etc.).
@@ -174,7 +178,7 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
isEditing?: boolean,
subject?: string,
message?: string,
- files?: any[],
+ files?: (CoreFileEntry | AddonModForumWSPostAttachment)[],
isPrivate?: boolean,
): void {
// Delete the local files from the tmp folder if any.
@@ -241,10 +245,64 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
/**
* Shows a form modal to edit an online post.
*/
- editPost(): void {
- alert('Edit post not implemented');
+ async editPost(): Promise {
+ const modal = await ModalController.instance.create({
+ component: AddonModForumEditPostComponent,
+ componentProps: {
+ post: this.post,
+ component: this.component,
+ componentId: this.componentId,
+ forum: this.forum,
+ },
+ backdropDismiss: false,
+ });
- // @todo
+ modal.present();
+
+ const result = await modal.onDidDismiss();
+ const data = result.data;
+
+ if (!data) {
+ return;
+ }
+
+ // Add some HTML to the message if needed.
+ const message = CoreTextUtils.instance.formatHtmlLines(data.message);
+ const files = data.files;
+ const options: AddonModForumUpdateDiscussionPostWSOptionsObject = {};
+
+ const sendingModal = await CoreDomUtils.instance.showModalLoading('core.sending', true);
+
+ try {
+ // Upload attachments first if any.
+ if (files.length) {
+ const attachment = await AddonModForumHelper.instance.uploadOrStoreReplyFiles(
+ this.forum.id,
+ this.post.id,
+ files,
+ false,
+ );
+
+ options.attachmentsid = attachment;
+ }
+
+ // Try to send it to server.
+ const sent = await AddonModForum.instance.updatePost(this.post.id, data.subject, message, options);
+
+ if (sent && this.forum.id) {
+ // Data sent to server, delete stored files (if any).
+ AddonModForumHelper.instance.deleteReplyStoredFiles(this.forum.id, this.post.id);
+
+ this.onPostChange.emit();
+ this.post.subject = data.subject;
+ this.post.message = message;
+ this.post.attachments = data.files;
+ }
+ } catch (error) {
+ CoreDomUtils.instance.showErrorModalDefault(error, 'addon.mod_forum.couldnotupdate', true);
+ } finally {
+ sendingModal.dismiss();
+ }
}
/**
diff --git a/src/addons/mod/forum/services/forum.service.ts b/src/addons/mod/forum/services/forum.service.ts
index 3a42d6cf8..1517839bf 100644
--- a/src/addons/mod/forum/services/forum.service.ts
+++ b/src/addons/mod/forum/services/forum.service.ts
@@ -1600,6 +1600,16 @@ export type AddonModForumAccessInformation = {
cangrade?: boolean; // Whether the user has the capability mod/forum:grade allowed.
};
+/**
+ * Reply info.
+ */
+export type AddonModForumReply = {
+ id: number;
+ subject: string;
+ message: string;
+ files: (CoreFileEntry | AddonModForumWSPostAttachment)[];
+};
+
/**
* Can add discussion info.
*/