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 }} + + + + + + + + +
+ + {{ 'addon.mod_forum.subject' | translate }} + + + + {{ 'addon.mod_forum.message' | translate }} + + + + + + {{ 'addon.mod_forum.advanced' | translate }} + + + + + + + + {{ 'core.savechanges' | translate }} + + + {{ 'core.cancel' | 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. */