commit
5dd2f2c93d
|
@ -21,7 +21,6 @@ import { CoreTagComponentsModule } from '@features/tag/components/components.mod
|
||||||
import { CoreRatingComponentsModule } from '@features/rating/components/components.module';
|
import { CoreRatingComponentsModule } from '@features/rating/components/components.module';
|
||||||
|
|
||||||
import { AddonModForumDiscussionOptionsMenuComponent } from './discussion-options-menu/discussion-options-menu';
|
import { AddonModForumDiscussionOptionsMenuComponent } from './discussion-options-menu/discussion-options-menu';
|
||||||
import { AddonModForumEditPostComponent } from './edit-post/edit-post';
|
|
||||||
import { AddonModForumIndexComponent } from './index/index';
|
import { AddonModForumIndexComponent } from './index/index';
|
||||||
import { AddonModForumPostComponent } from './post/post';
|
import { AddonModForumPostComponent } from './post/post';
|
||||||
import { AddonModForumPostOptionsMenuComponent } from './post-options-menu/post-options-menu';
|
import { AddonModForumPostOptionsMenuComponent } from './post-options-menu/post-options-menu';
|
||||||
|
@ -30,7 +29,6 @@ import { AddonModForumSortOrderSelectorComponent } from './sort-order-selector/s
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
AddonModForumDiscussionOptionsMenuComponent,
|
AddonModForumDiscussionOptionsMenuComponent,
|
||||||
AddonModForumEditPostComponent,
|
|
||||||
AddonModForumIndexComponent,
|
AddonModForumIndexComponent,
|
||||||
AddonModForumPostComponent,
|
AddonModForumPostComponent,
|
||||||
AddonModForumPostOptionsMenuComponent,
|
AddonModForumPostOptionsMenuComponent,
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
<ion-header>
|
|
||||||
<ion-toolbar>
|
|
||||||
<h2>{{ 'addon.mod_forum.yourreply' | translate }}</h2>
|
|
||||||
<ion-buttons slot="end">
|
|
||||||
<ion-button fill="clear" (click)="closeModal()" [attr.aria-label]="'core.close' | translate">
|
|
||||||
<ion-icon name="fas-times" slot="icon-only" aria-hidden="true"></ion-icon>
|
|
||||||
</ion-button>
|
|
||||||
</ion-buttons>
|
|
||||||
</ion-toolbar>
|
|
||||||
</ion-header>
|
|
||||||
<ion-content>
|
|
||||||
<form #editFormEl>
|
|
||||||
<ion-item>
|
|
||||||
<ion-label position="stacked">{{ 'addon.mod_forum.subject' | translate }}</ion-label>
|
|
||||||
<ion-input type="text" [placeholder]="'addon.mod_forum.subject' | translate" [(ngModel)]="replyData.subject" name="subject">
|
|
||||||
</ion-input>
|
|
||||||
</ion-item>
|
|
||||||
<ion-item>
|
|
||||||
<ion-label position="stacked">{{ 'addon.mod_forum.message' | translate }}</ion-label>
|
|
||||||
<core-rich-text-editor elementId="message"
|
|
||||||
[name]="'mod_forum_reply_' + replyData.id" [control]="messageControl"
|
|
||||||
[placeholder]="'addon.mod_forum.replyplaceholder' | translate" [autoSave]="true"
|
|
||||||
[component]="component" [componentId]="componentId" [draftExtraParams]="{edit: replyData.id}"
|
|
||||||
contextLevel="module" [contextInstanceId]="forum.cmid"
|
|
||||||
(contentChanged)="onMessageChange($event)">
|
|
||||||
</core-rich-text-editor>
|
|
||||||
</ion-item>
|
|
||||||
<ion-item
|
|
||||||
button class="divider ion-text-wrap"
|
|
||||||
(click)="toggleAdvanced()"
|
|
||||||
role="heading"
|
|
||||||
detail="false"
|
|
||||||
[attr.aria-expanded]="advanced"
|
|
||||||
aria-controls="addon-mod-forum-advanced"
|
|
||||||
[attr.aria-label]="(advanced ? 'core.hideadvanced' : 'core.showadvanced') | translate"
|
|
||||||
>
|
|
||||||
<ion-icon *ngIf="!advanced" name="fas-caret-right" flip-rtl slot="start" aria-hidden="true"></ion-icon>
|
|
||||||
<ion-icon *ngIf="advanced" name="fas-caret-down" slot="start" aria-hidden="true"></ion-icon>
|
|
||||||
<ion-label><h2>{{ 'addon.mod_forum.advanced' | translate }}</h2></ion-label>
|
|
||||||
</ion-item>
|
|
||||||
<div *ngIf="advanced" id="addon-mod-forum-advanced">
|
|
||||||
<core-attachments *ngIf="forum.id && forum.maxattachments > 0"
|
|
||||||
[maxSize]="forum.maxbytes" [maxSubmissions]="forum.maxattachments" [allowOffline]="true" [files]="replyData.files"
|
|
||||||
[component]="component" [componentId]="forum.cmid" [courseId]="forum.course">
|
|
||||||
</core-attachments>
|
|
||||||
</div>
|
|
||||||
<ion-grid>
|
|
||||||
<ion-row>
|
|
||||||
<ion-col>
|
|
||||||
<ion-button expand="block" (click)="reply($event)" [disabled]="replyData.subject == '' || replyData.message == null">
|
|
||||||
{{ 'core.savechanges' | translate }}
|
|
||||||
</ion-button>
|
|
||||||
</ion-col>
|
|
||||||
<ion-col>
|
|
||||||
<ion-button expand="block" color="light" (click)="closeModal()">{{ 'core.cancel' | translate }}</ion-button>
|
|
||||||
</ion-col>
|
|
||||||
</ion-row>
|
|
||||||
</ion-grid>
|
|
||||||
</form>
|
|
||||||
</ion-content>
|
|
|
@ -1,150 +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, ViewChild, ElementRef, Input, OnInit } from '@angular/core';
|
|
||||||
import { FormControl } from '@angular/forms';
|
|
||||||
import { 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';
|
|
||||||
import { AddonModForumHelper } from '@addons/mod/forum/services/forum-helper';
|
|
||||||
import { CoreForms } from '@singletons/form';
|
|
||||||
import { CoreFileEntry } from '@services/file-helper';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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<AddonModForumReply, 'id'>; // 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.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<void> {
|
|
||||||
const confirmDismiss = await this.confirmDismiss();
|
|
||||||
|
|
||||||
if (!confirmDismiss) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data) {
|
|
||||||
CoreForms.triggerFormSubmittedEvent(this.formElement, false, CoreSites.getCurrentSiteId());
|
|
||||||
} else {
|
|
||||||
CoreForms.triggerFormCancelledEvent(this.formElement, CoreSites.getCurrentSiteId());
|
|
||||||
}
|
|
||||||
|
|
||||||
ModalController.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<boolean> {
|
|
||||||
if (this.forceLeave || !AddonModForumHelper.hasPostDataChanged(this.replyData, this.originalData)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Show confirmation if some data has been modified.
|
|
||||||
await CoreDomUtils.showConfirm(Translate.instant('core.confirmcanceledit'));
|
|
||||||
|
|
||||||
// Delete the local files from the tmp folder.
|
|
||||||
CoreFileUploader.clearTmpFiles(this.replyData.files as CoreFileEntry[]);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch (error) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -122,11 +122,7 @@ export class AddonModForumPostOptionsMenuComponent implements OnInit, OnDestroy
|
||||||
* Edit a post.
|
* Edit a post.
|
||||||
*/
|
*/
|
||||||
editPost(): void {
|
editPost(): void {
|
||||||
if (!this.offlinePost) {
|
|
||||||
PopoverController.dismiss({ action: 'edit' });
|
PopoverController.dismiss({ action: 'edit' });
|
||||||
} else {
|
|
||||||
PopoverController.dismiss({ action: 'editoffline' });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<div class="addon-mod_forum-post">
|
<div class="addon-mod_forum-post">
|
||||||
|
<ng-container *ngIf="!formData.isEditing || !showForm">
|
||||||
<ion-card-header class="ion-text-wrap ion-no-padding" id="addon-mod_forum-post-{{post.id}}">
|
<ion-card-header class="ion-text-wrap ion-no-padding" id="addon-mod_forum-post-{{post.id}}">
|
||||||
<ion-item class="ion-text-wrap" [class.highlight]="highlight" lines="none">
|
<ion-item class="ion-text-wrap" [class.highlight]="highlight" lines="none">
|
||||||
<ion-label>
|
<ion-label>
|
||||||
|
@ -16,8 +17,8 @@
|
||||||
contextLevel="module" [contextInstanceId]="forum && forum.cmid" [courseId]="courseId">
|
contextLevel="module" [contextInstanceId]="forum && forum.cmid" [courseId]="courseId">
|
||||||
</core-format-text>
|
</core-format-text>
|
||||||
</h2>
|
</h2>
|
||||||
<ion-note *ngIf="trackPosts && post.unread"
|
<ion-note *ngIf="trackPosts && post.unread" class="ion-float-end ion-padding-start ion-text-end"
|
||||||
class="ion-float-end ion-padding-start ion-text-end" [attr.aria-label]="'addon.mod_forum.unread' | translate">
|
[attr.aria-label]="'addon.mod_forum.unread' | translate">
|
||||||
<ion-icon name="fas-circle" color="primary" aria-hidden="true"></ion-icon>
|
<ion-icon name="fas-circle" color="primary" aria-hidden="true"></ion-icon>
|
||||||
</ion-note>
|
</ion-note>
|
||||||
<ion-button *ngIf="optionsMenuEnabled"
|
<ion-button *ngIf="optionsMenuEnabled"
|
||||||
|
@ -28,7 +29,8 @@
|
||||||
</ion-button>
|
</ion-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="addon-mod-forum-post-info">
|
<div class="addon-mod-forum-post-info">
|
||||||
<core-user-avatar *ngIf="post.author && post.author.fullname" [user]="post.author" slot="start" [courseId]="courseId">
|
<core-user-avatar *ngIf="post.author && post.author.fullname" [user]="post.author" slot="start"
|
||||||
|
[courseId]="courseId">
|
||||||
</core-user-avatar>
|
</core-user-avatar>
|
||||||
<div class="addon-mod-forum-post-author">
|
<div class="addon-mod-forum-post-author">
|
||||||
<span *ngIf="post.author && post.author.fullname">{{post.author.fullname}}</span>
|
<span *ngIf="post.author && post.author.fullname">{{post.author.fullname}}</span>
|
||||||
|
@ -44,8 +46,8 @@
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<ng-container *ngIf="!displaySubject">
|
<ng-container *ngIf="!displaySubject">
|
||||||
<ion-note *ngIf="trackPosts && post.unread"
|
<ion-note *ngIf="trackPosts && post.unread" class="ion-float-end ion-padding-start ion-text-end"
|
||||||
class="ion-float-end ion-padding-start ion-text-end" [attr.aria-label]="'addon.mod_forum.unread' | translate">
|
[attr.aria-label]="'addon.mod_forum.unread' | translate">
|
||||||
<ion-icon name="fas-circle" color="primary" aria-hidden="true"></ion-icon>
|
<ion-icon name="fas-circle" color="primary" aria-hidden="true"></ion-icon>
|
||||||
</ion-note>
|
</ion-note>
|
||||||
<ion-button *ngIf="optionsMenuEnabled"
|
<ion-button *ngIf="optionsMenuEnabled"
|
||||||
|
@ -92,7 +94,7 @@
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<ion-button fill="clear" size="small"
|
<ion-button fill="clear" size="small"
|
||||||
[attr.aria-controls]="'addon-forum-reply-edit-form-' + uniqueId"
|
[attr.aria-controls]="'addon-forum-reply-edit-form-' + uniqueId"
|
||||||
[attr.aria-expanded]="replyData.replyingTo === post.id"
|
[attr.aria-expanded]="formData.replyingTo === post.id"
|
||||||
(click)="showReplyForm($event)">
|
(click)="showReplyForm($event)">
|
||||||
<ion-icon name="fas-reply" slot="start" aria-hidden="true"></ion-icon>
|
<ion-icon name="fas-reply" slot="start" aria-hidden="true"></ion-icon>
|
||||||
{{ 'addon.mod_forum.reply' | translate }}
|
{{ 'addon.mod_forum.reply' | translate }}
|
||||||
|
@ -100,12 +102,14 @@
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
</div>
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
<form *ngIf="showForm"
|
<form *ngIf="showForm"
|
||||||
[id]="'addon-forum-reply-edit-form-' + uniqueId" #replyFormEl>
|
[id]="'addon-forum-reply-edit-form-' + uniqueId" #replyFormEl>
|
||||||
<ion-item>
|
<ion-item>
|
||||||
<ion-label position="stacked">{{ 'addon.mod_forum.subject' | translate }}</ion-label>
|
<ion-label position="stacked">{{ 'addon.mod_forum.subject' | translate }}</ion-label>
|
||||||
<ion-input type="text" [placeholder]="'addon.mod_forum.subject' | translate" [(ngModel)]="replyData.subject" name="subject">
|
<ion-input type="text" [placeholder]="'addon.mod_forum.subject' | translate" [(ngModel)]="formData.subject"
|
||||||
|
name="subject">
|
||||||
</ion-input>
|
</ion-input>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-item>
|
<ion-item>
|
||||||
|
@ -119,7 +123,7 @@
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-item class="ion-text-wrap" *ngIf="accessInfo.canpostprivatereply">
|
<ion-item class="ion-text-wrap" *ngIf="accessInfo.canpostprivatereply">
|
||||||
<ion-label>{{ 'addon.mod_forum.privatereply' | translate }}</ion-label>
|
<ion-label>{{ 'addon.mod_forum.privatereply' | translate }}</ion-label>
|
||||||
<ion-checkbox slot="end" [(ngModel)]="replyData.isprivatereply" name="isprivatereply"></ion-checkbox>
|
<ion-checkbox slot="end" [(ngModel)]="formData.isprivatereply" name="isprivatereply"></ion-checkbox>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ng-container *ngIf="forum.id && forum.maxattachments > 0">
|
<ng-container *ngIf="forum.id && forum.maxattachments > 0">
|
||||||
<ion-item
|
<ion-item
|
||||||
|
@ -138,7 +142,7 @@
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<div *ngIf="advanced" [id]="'addon-forum-reply-edit-form-advanced-' + uniqueId">
|
<div *ngIf="advanced" [id]="'addon-forum-reply-edit-form-advanced-' + uniqueId">
|
||||||
<core-attachments
|
<core-attachments
|
||||||
[files]="replyData.files" [maxSize]="forum.maxbytes" [maxSubmissions]="forum.maxattachments"
|
[files]="formData.files" [maxSize]="forum.maxbytes" [maxSubmissions]="forum.maxattachments"
|
||||||
[component]="component" [componentId]="forum.cmid" [allowOffline]="true" [courseId]="courseId">
|
[component]="component" [componentId]="forum.cmid" [allowOffline]="true" [courseId]="courseId">
|
||||||
</core-attachments>
|
</core-attachments>
|
||||||
</div>
|
</div>
|
||||||
|
@ -146,7 +150,7 @@
|
||||||
<ion-grid>
|
<ion-grid>
|
||||||
<ion-row>
|
<ion-row>
|
||||||
<ion-col>
|
<ion-col>
|
||||||
<ion-button expand="block" (click)="reply()" [disabled]="replyData.subject == '' || replyData.message == null">
|
<ion-button expand="block" (click)="send()" [disabled]="formData.subject == '' || formData.message == null">
|
||||||
{{ 'addon.mod_forum.posttoforum' | translate }}
|
{{ 'addon.mod_forum.posttoforum' | translate }}
|
||||||
</ion-button>
|
</ion-button>
|
||||||
</ion-col>
|
</ion-col>
|
||||||
|
|
|
@ -36,8 +36,7 @@ import {
|
||||||
AddonModForumDiscussion,
|
AddonModForumDiscussion,
|
||||||
AddonModForumPost,
|
AddonModForumPost,
|
||||||
AddonModForumProvider,
|
AddonModForumProvider,
|
||||||
AddonModForumReply,
|
AddonModForumPostFormData,
|
||||||
AddonModForumUpdateDiscussionPostWSOptionsObject,
|
|
||||||
} from '../../services/forum';
|
} from '../../services/forum';
|
||||||
import { CoreTag } from '@features/tag/services/tag';
|
import { CoreTag } from '@features/tag/services/tag';
|
||||||
import { Translate } from '@singletons';
|
import { Translate } from '@singletons';
|
||||||
|
@ -47,13 +46,13 @@ import { AddonModForumSync } from '../../services/forum-sync';
|
||||||
import { CoreSync } from '@services/sync';
|
import { CoreSync } from '@services/sync';
|
||||||
import { CoreTextUtils } from '@services/utils/text';
|
import { CoreTextUtils } from '@services/utils/text';
|
||||||
import { AddonModForumHelper } from '../../services/forum-helper';
|
import { AddonModForumHelper } from '../../services/forum-helper';
|
||||||
import { AddonModForumOffline, AddonModForumReplyOptions } from '../../services/forum-offline';
|
import { AddonModForumOffline } from '../../services/forum-offline';
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
import { AddonModForumPostOptionsMenuComponent } from '../post-options-menu/post-options-menu';
|
import { AddonModForumPostOptionsMenuComponent } from '../post-options-menu/post-options-menu';
|
||||||
import { AddonModForumEditPostComponent } from '../edit-post/edit-post';
|
|
||||||
import { CoreRatingInfo } from '@features/rating/services/rating';
|
import { CoreRatingInfo } from '@features/rating/services/rating';
|
||||||
import { CoreForms } from '@singletons/form';
|
import { CoreForms } from '@singletons/form';
|
||||||
import { CoreFileEntry } from '@services/file-helper';
|
import { CoreFileEntry } from '@services/file-helper';
|
||||||
|
import { AddonModForumSharedPostFormData } from '../../pages/discussion/discussion.page';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Components that shows a discussion post, its attachments and the action buttons allowed (reply, etc.).
|
* Components that shows a discussion post, its attachments and the action buttons allowed (reply, etc.).
|
||||||
|
@ -71,8 +70,8 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
|
||||||
@Input() discussion?: AddonModForumDiscussion; // Post's' discussion, only for starting posts.
|
@Input() discussion?: AddonModForumDiscussion; // Post's' discussion, only for starting posts.
|
||||||
@Input() component!: string; // Component this post belong to.
|
@Input() component!: string; // Component this post belong to.
|
||||||
@Input() componentId!: number; // Component ID.
|
@Input() componentId!: number; // Component ID.
|
||||||
@Input() replyData!: AddonModForumReply; // Object with the new post data. Usually shared between posts.
|
@Input() formData!: AddonModForumSharedPostFormData; // Object with the new post data. Usually shared between posts.
|
||||||
@Input() originalData!: Omit<AddonModForumReply, 'id'>; // Object with the original post data. Usually shared between posts.
|
@Input() originalData!: Omit<AddonModForumPostFormData, 'id'>; // Original post data. Usually shared between posts.
|
||||||
@Input() trackPosts!: boolean; // True if post is being tracked.
|
@Input() trackPosts!: boolean; // True if post is being tracked.
|
||||||
@Input() forum!: AddonModForumData; // The forum the post belongs to. Required for attachments and offline posts.
|
@Input() forum!: AddonModForumData; // The forum the post belongs to. Required for attachments and offline posts.
|
||||||
@Input() accessInfo!: AddonModForumAccessInformation; // Forum access information.
|
@Input() accessInfo!: AddonModForumAccessInformation; // Forum access information.
|
||||||
|
@ -93,8 +92,6 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
|
||||||
displaySubject = true;
|
displaySubject = true;
|
||||||
optionsMenuEnabled = false;
|
optionsMenuEnabled = false;
|
||||||
|
|
||||||
protected syncId!: string;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected elementRef: ElementRef,
|
protected elementRef: ElementRef,
|
||||||
@Optional() protected content?: IonContent,
|
@Optional() protected content?: IonContent,
|
||||||
|
@ -102,8 +99,9 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
|
||||||
|
|
||||||
get showForm(): boolean {
|
get showForm(): boolean {
|
||||||
return this.post.id > 0
|
return this.post.id > 0
|
||||||
? !this.replyData.isEditing && this.replyData.replyingTo === this.post.id
|
? (!this.formData.isEditing && this.formData.replyingTo === this.post.id) ||
|
||||||
: !!this.replyData.isEditing && this.replyData.replyingTo === this.post.parentid;
|
(!!this.formData.isEditing && this.formData.id === this.post.id)
|
||||||
|
: !!this.formData.isEditing && this.formData.replyingTo === this.post.parentid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -172,44 +170,47 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set data to new reply post, clearing temporary files and updating original data.
|
* Set data to new/edit post, clearing temporary files and updating original data.
|
||||||
*
|
*
|
||||||
* @param replyingTo Id of post beeing replied.
|
* @param replyingTo Id of post beeing replied.
|
||||||
* @param isEditing True it's an offline reply beeing edited, false otherwise.
|
* @param isEditing True it's an offline reply beeing edited, false otherwise.
|
||||||
* @param subject Subject of the reply.
|
* @param subject Subject of the reply.
|
||||||
* @param message Message of the reply.
|
* @param message Message of the reply.
|
||||||
* @param isPrivate True if it's private reply.
|
|
||||||
* @param files Reply attachments.
|
* @param files Reply attachments.
|
||||||
|
* @param isPrivate True if it's private reply.
|
||||||
|
* @param postId The post ID if user is editing an online post.
|
||||||
*/
|
*/
|
||||||
protected setReplyFormData(
|
protected setFormData(
|
||||||
replyingTo?: number,
|
replyingTo?: number,
|
||||||
isEditing?: boolean,
|
isEditing?: boolean,
|
||||||
subject?: string,
|
subject?: string,
|
||||||
message?: string,
|
message?: string,
|
||||||
files?: CoreFileEntry[],
|
files?: CoreFileEntry[],
|
||||||
isPrivate?: boolean,
|
isPrivate?: boolean,
|
||||||
|
postId?: number,
|
||||||
): void {
|
): void {
|
||||||
// Delete the local files from the tmp folder if any.
|
// Delete the local files from the tmp folder if any.
|
||||||
CoreFileUploader.clearTmpFiles(this.replyData.files);
|
CoreFileUploader.clearTmpFiles(this.formData.files);
|
||||||
|
|
||||||
this.replyData.replyingTo = replyingTo || 0;
|
this.formData.replyingTo = replyingTo || 0;
|
||||||
this.replyData.isEditing = !!isEditing;
|
this.formData.isEditing = !!isEditing;
|
||||||
this.replyData.subject = subject || this.defaultReplySubject || '';
|
this.formData.subject = subject || this.defaultReplySubject || '';
|
||||||
this.replyData.message = message || null;
|
this.formData.message = message || null;
|
||||||
this.replyData.files = files || [];
|
this.formData.files = files || [];
|
||||||
this.replyData.isprivatereply = !!isPrivate;
|
this.formData.isprivatereply = !!isPrivate;
|
||||||
|
this.formData.id = postId;
|
||||||
|
|
||||||
// Update rich text editor.
|
// Update rich text editor.
|
||||||
this.messageControl.setValue(this.replyData.message);
|
this.messageControl.setValue(this.formData.message);
|
||||||
|
|
||||||
// Update original data.
|
// Update original data.
|
||||||
this.originalData.subject = this.replyData.subject;
|
this.originalData.subject = this.formData.subject;
|
||||||
this.originalData.message = this.replyData.message;
|
this.originalData.message = this.formData.message;
|
||||||
this.originalData.files = this.replyData.files.slice();
|
this.originalData.files = this.formData.files.slice();
|
||||||
this.originalData.isprivatereply = this.replyData.isprivatereply;
|
this.originalData.isprivatereply = this.formData.isprivatereply;
|
||||||
|
|
||||||
// Show advanced fields if any of them has not the default value.
|
// Show advanced fields if any of them has not the default value.
|
||||||
this.advanced = this.replyData.files.length > 0;
|
this.advanced = this.formData.files.length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -226,6 +227,7 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
|
||||||
cmId: this.forum.cmid,
|
cmId: this.forum.cmid,
|
||||||
},
|
},
|
||||||
event,
|
event,
|
||||||
|
waitForDismissCompleted: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (popoverData && popoverData.action) {
|
if (popoverData && popoverData.action) {
|
||||||
|
@ -233,9 +235,6 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
|
||||||
case 'edit':
|
case 'edit':
|
||||||
this.editPost();
|
this.editPost();
|
||||||
break;
|
break;
|
||||||
case 'editoffline':
|
|
||||||
this.editOfflineReply();
|
|
||||||
break;
|
|
||||||
case 'delete':
|
case 'delete':
|
||||||
this.deletePost();
|
this.deletePost();
|
||||||
break;
|
break;
|
||||||
|
@ -246,65 +245,6 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows a form modal to edit an online post.
|
|
||||||
*/
|
|
||||||
async editPost(): Promise<void> {
|
|
||||||
const modalData = await CoreDomUtils.openModal<AddonModForumReply>({
|
|
||||||
component: AddonModForumEditPostComponent,
|
|
||||||
componentProps: {
|
|
||||||
post: this.post,
|
|
||||||
component: this.component,
|
|
||||||
componentId: this.componentId,
|
|
||||||
forum: this.forum,
|
|
||||||
},
|
|
||||||
backdropDismiss: false,
|
|
||||||
cssClass: 'core-modal-fullscreen',
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!modalData) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add some HTML to the message if needed.
|
|
||||||
const message = CoreTextUtils.formatHtmlLines(modalData.message!);
|
|
||||||
const files = modalData.files;
|
|
||||||
const options: AddonModForumUpdateDiscussionPostWSOptionsObject = {};
|
|
||||||
|
|
||||||
const sendingModal = await CoreDomUtils.showModalLoading('core.sending', true);
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Upload attachments first if any.
|
|
||||||
if (files.length) {
|
|
||||||
const attachment = await AddonModForumHelper.uploadOrStoreReplyFiles(
|
|
||||||
this.forum.id,
|
|
||||||
this.post.id,
|
|
||||||
files as CoreFileEntry[],
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
|
|
||||||
options.attachmentsid = attachment;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to send it to server.
|
|
||||||
const sent = await AddonModForum.updatePost(this.post.id, modalData.subject!, message, options);
|
|
||||||
|
|
||||||
if (sent && this.forum.id) {
|
|
||||||
// Data sent to server, delete stored files (if any).
|
|
||||||
AddonModForumHelper.deleteReplyStoredFiles(this.forum.id, this.post.id);
|
|
||||||
|
|
||||||
this.onPostChange.emit();
|
|
||||||
this.post.subject = modalData.subject!;
|
|
||||||
this.post.message = message;
|
|
||||||
this.post.attachments = modalData.files;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
CoreDomUtils.showErrorModalDefault(error, 'addon.mod_forum.couldnotupdate', true);
|
|
||||||
} finally {
|
|
||||||
sendingModal.dismiss();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set this post as being replied to.
|
* Set this post as being replied to.
|
||||||
*
|
*
|
||||||
|
@ -314,21 +254,13 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
|
||||||
if (this.replyData.isEditing) {
|
if (this.formData.isEditing) {
|
||||||
// User is editing a post, data needs to be resetted. Ask confirm if there is unsaved data.
|
// User is editing a post, data needs to be resetted. Ask confirm if there is unsaved data.
|
||||||
try {
|
try {
|
||||||
await this.confirmDiscard();
|
await this.confirmDiscard();
|
||||||
this.setReplyFormData(this.post.id);
|
this.setFormData(this.post.id);
|
||||||
|
|
||||||
if (this.content) {
|
this.scrollToForm();
|
||||||
setTimeout(() => {
|
|
||||||
CoreDomUtils.scrollToElementBySelector(
|
|
||||||
this.elementRef.nativeElement,
|
|
||||||
this.content,
|
|
||||||
'#addon-forum-reply-edit-form-' + this.uniqueId,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch {
|
} catch {
|
||||||
// Cancelled.
|
// Cancelled.
|
||||||
}
|
}
|
||||||
|
@ -336,53 +268,47 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.replyData.replyingTo) {
|
if (!this.formData.replyingTo) {
|
||||||
// User isn't replying, it's a brand new reply. Initialize the data.
|
// User isn't replying, it's a brand new reply. Initialize the data.
|
||||||
this.setReplyFormData(this.post.id);
|
this.setFormData(this.post.id);
|
||||||
} else {
|
} else {
|
||||||
// The post being replied has changed but the data will be kept.
|
// The post being replied has changed but the data will be kept.
|
||||||
this.replyData.replyingTo = this.post.id;
|
this.formData.replyingTo = this.post.id;
|
||||||
|
|
||||||
if (this.replyData.subject == this.originalData.subject) {
|
if (this.formData.subject == this.originalData.subject) {
|
||||||
// Update subject only if it hadn't been modified
|
// Update subject only if it hadn't been modified
|
||||||
this.replyData.subject = this.defaultReplySubject;
|
this.formData.subject = this.defaultReplySubject;
|
||||||
this.originalData.subject = this.defaultReplySubject;
|
this.originalData.subject = this.defaultReplySubject;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.messageControl.setValue(this.replyData.message);
|
this.messageControl.setValue(this.formData.message);
|
||||||
}
|
|
||||||
|
|
||||||
if (this.content) {
|
|
||||||
setTimeout(() => {
|
|
||||||
CoreDomUtils.scrollToElementBySelector(
|
|
||||||
this.elementRef.nativeElement,
|
|
||||||
this.content,
|
|
||||||
'#addon-forum-reply-edit-form-' + this.uniqueId,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.scrollToForm();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set this post as being edited to.
|
* Set this post as being edited to.
|
||||||
*/
|
*/
|
||||||
async editOfflineReply(): Promise<void> {
|
async editPost(): Promise<void> {
|
||||||
// Ask confirm if there is unsaved data.
|
// Ask confirm if there is unsaved data.
|
||||||
try {
|
try {
|
||||||
await this.confirmDiscard();
|
await this.confirmDiscard();
|
||||||
|
|
||||||
this.syncId = AddonModForumSync.getDiscussionSyncId(this.discussionId);
|
this.formData.syncId = AddonModForumSync.getDiscussionSyncId(this.discussionId);
|
||||||
CoreSync.blockOperation(AddonModForumProvider.COMPONENT, this.syncId);
|
CoreSync.blockOperation(AddonModForumProvider.COMPONENT, this.formData.syncId);
|
||||||
|
|
||||||
this.setReplyFormData(
|
this.setFormData(
|
||||||
this.post.parentid,
|
this.post.parentid,
|
||||||
true,
|
true,
|
||||||
this.post.subject,
|
this.post.subject,
|
||||||
this.post.message,
|
this.post.message,
|
||||||
this.post.attachments,
|
this.post.attachments,
|
||||||
this.post.isprivatereply,
|
this.post.isprivatereply,
|
||||||
|
this.post.id > 0 ? this.post.id : undefined,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.scrollToForm(5);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Cancelled.
|
// Cancelled.
|
||||||
}
|
}
|
||||||
|
@ -394,53 +320,53 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
|
||||||
* @param text The new text.
|
* @param text The new text.
|
||||||
*/
|
*/
|
||||||
onMessageChange(text: string): void {
|
onMessageChange(text: string): void {
|
||||||
this.replyData.message = text;
|
this.formData.message = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reply to this post.
|
* Reply to this post or edit post data.
|
||||||
*/
|
*/
|
||||||
async reply(): Promise<void> {
|
async send(): Promise<void> {
|
||||||
if (!this.replyData.subject) {
|
if (!this.formData.subject) {
|
||||||
CoreDomUtils.showErrorModal('addon.mod_forum.erroremptysubject', true);
|
CoreDomUtils.showErrorModal('addon.mod_forum.erroremptysubject', true);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.replyData.message) {
|
if (!this.formData.message) {
|
||||||
CoreDomUtils.showErrorModal('addon.mod_forum.erroremptymessage', true);
|
CoreDomUtils.showErrorModal('addon.mod_forum.erroremptymessage', true);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let saveOffline = false;
|
let saveOffline = false;
|
||||||
let message = this.replyData.message;
|
let message = this.formData.message;
|
||||||
const subject = this.replyData.subject;
|
const subject = this.formData.subject;
|
||||||
const replyingTo = this.replyData.replyingTo!;
|
const replyingTo = this.formData.replyingTo!;
|
||||||
const files = this.replyData.files || [];
|
const files = this.formData.files || [];
|
||||||
const options: AddonModForumReplyOptions = {};
|
const isEditOnline = this.formData.id && this.formData.id > 0;
|
||||||
const modal = await CoreDomUtils.showModalLoading('core.sending', true);
|
const modal = await CoreDomUtils.showModalLoading('core.sending', true);
|
||||||
|
|
||||||
// Add some HTML to the message if needed.
|
// Add some HTML to the message if needed.
|
||||||
message = CoreTextUtils.formatHtmlLines(message);
|
message = CoreTextUtils.formatHtmlLines(message);
|
||||||
|
|
||||||
// Set private option if checked.
|
|
||||||
if (this.replyData.isprivatereply) {
|
|
||||||
options.private = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Upload attachments first if any.
|
// Upload attachments first if any.
|
||||||
let attachments;
|
let attachments;
|
||||||
|
|
||||||
|
try {
|
||||||
if (files.length) {
|
if (files.length) {
|
||||||
try {
|
try {
|
||||||
attachments = await AddonModForumHelper.uploadOrStoreReplyFiles(this.forum.id, replyingTo, files, false);
|
attachments = await AddonModForumHelper.uploadOrStoreReplyFiles(
|
||||||
|
this.forum.id,
|
||||||
|
isEditOnline ? this.formData.id! : replyingTo,
|
||||||
|
files,
|
||||||
|
false,
|
||||||
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
||||||
// Cannot upload them in online, save them in offline.
|
// Cannot upload them in online, save them in offline.
|
||||||
if (!this.forum.id) {
|
if (!this.forum.id || isEditOnline) {
|
||||||
// Cannot store them in offline without the forum ID. Reject.
|
// Cannot store them in offline. Reject.
|
||||||
return Promise.reject(error);
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
saveOffline = true;
|
saveOffline = true;
|
||||||
|
@ -448,13 +374,13 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
let sent = false;
|
||||||
if (attachments) {
|
|
||||||
options.attachmentsid = attachments;
|
|
||||||
}
|
|
||||||
|
|
||||||
let sent;
|
if (isEditOnline) {
|
||||||
if (saveOffline) {
|
sent = await AddonModForum.updatePost(this.formData.id!, subject, message, {
|
||||||
|
attachmentsid: attachments,
|
||||||
|
});
|
||||||
|
} else if (saveOffline) {
|
||||||
// Save post in offline.
|
// Save post in offline.
|
||||||
await AddonModForumOffline.replyPost(
|
await AddonModForumOffline.replyPost(
|
||||||
replyingTo,
|
replyingTo,
|
||||||
|
@ -464,7 +390,10 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
|
||||||
this.courseId,
|
this.courseId,
|
||||||
subject,
|
subject,
|
||||||
message,
|
message,
|
||||||
options,
|
{
|
||||||
|
attachmentsid: attachments,
|
||||||
|
private: !!this.formData.isprivatereply,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Set sent to false since it wasn't sent to server.
|
// Set sent to false since it wasn't sent to server.
|
||||||
|
@ -480,7 +409,10 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
|
||||||
this.courseId,
|
this.courseId,
|
||||||
subject,
|
subject,
|
||||||
message,
|
message,
|
||||||
options,
|
{
|
||||||
|
attachmentsid: attachments,
|
||||||
|
private: !!this.formData.isprivatereply,
|
||||||
|
},
|
||||||
undefined,
|
undefined,
|
||||||
!files.length,
|
!files.length,
|
||||||
);
|
);
|
||||||
|
@ -492,17 +424,19 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset data.
|
// Reset data.
|
||||||
this.setReplyFormData();
|
this.setFormData();
|
||||||
|
|
||||||
this.onPostChange.emit();
|
this.onPostChange.emit();
|
||||||
|
|
||||||
CoreForms.triggerFormSubmittedEvent(this.formElement, sent, CoreSites.getCurrentSiteId());
|
CoreForms.triggerFormSubmittedEvent(this.formElement, sent, CoreSites.getCurrentSiteId());
|
||||||
|
|
||||||
if (this.syncId) {
|
this.unblockOperation();
|
||||||
CoreSync.unblockOperation(AddonModForumProvider.COMPONENT, this.syncId);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
CoreDomUtils.showErrorModalDefault(error, 'addon.mod_forum.couldnotadd', true);
|
CoreDomUtils.showErrorModalDefault(
|
||||||
|
error,
|
||||||
|
isEditOnline ? 'addon.mod_forum.couldnotupdate' : 'addon.mod_forum.couldnotadd',
|
||||||
|
true,
|
||||||
|
);
|
||||||
} finally {
|
} finally {
|
||||||
modal.dismiss();
|
modal.dismiss();
|
||||||
}
|
}
|
||||||
|
@ -516,13 +450,11 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
|
||||||
await this.confirmDiscard();
|
await this.confirmDiscard();
|
||||||
|
|
||||||
// Reset data.
|
// Reset data.
|
||||||
this.setReplyFormData();
|
this.setFormData();
|
||||||
|
|
||||||
CoreForms.triggerFormCancelledEvent(this.formElement, CoreSites.getCurrentSiteId());
|
CoreForms.triggerFormCancelledEvent(this.formElement, CoreSites.getCurrentSiteId());
|
||||||
|
|
||||||
if (this.syncId) {
|
this.unblockOperation();
|
||||||
CoreSync.unblockOperation(AddonModForumProvider.COMPONENT, this.syncId);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Cancelled.
|
// Cancelled.
|
||||||
}
|
}
|
||||||
|
@ -548,13 +480,11 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
|
||||||
await CoreUtils.ignoreErrors(Promise.all(promises));
|
await CoreUtils.ignoreErrors(Promise.all(promises));
|
||||||
|
|
||||||
// Reset data.
|
// Reset data.
|
||||||
this.setReplyFormData();
|
this.setFormData();
|
||||||
|
|
||||||
this.onPostChange.emit();
|
this.onPostChange.emit();
|
||||||
|
|
||||||
if (this.syncId) {
|
this.unblockOperation();
|
||||||
CoreSync.unblockOperation(AddonModForumProvider.COMPONENT, this.syncId);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Cancelled.
|
// Cancelled.
|
||||||
}
|
}
|
||||||
|
@ -578,9 +508,7 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
|
||||||
* Component being destroyed.
|
* Component being destroyed.
|
||||||
*/
|
*/
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
if (this.syncId) {
|
this.unblockOperation();
|
||||||
CoreSync.unblockOperation(AddonModForumProvider.COMPONENT, this.syncId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -588,13 +516,45 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
|
||||||
*
|
*
|
||||||
* @return Promise resolved if the user confirms or data was not changed and rejected otherwise.
|
* @return Promise resolved if the user confirms or data was not changed and rejected otherwise.
|
||||||
*/
|
*/
|
||||||
protected confirmDiscard(): Promise<void> {
|
protected async confirmDiscard(): Promise<void> {
|
||||||
if (AddonModForumHelper.hasPostDataChanged(this.replyData, this.originalData)) {
|
if (AddonModForumHelper.hasPostDataChanged(this.formData, this.originalData)) {
|
||||||
// Show confirmation if some data has been modified.
|
// Show confirmation if some data has been modified.
|
||||||
return CoreDomUtils.showConfirm(Translate.instant('core.confirmloss'));
|
await CoreDomUtils.showConfirm(Translate.instant('core.confirmloss'));
|
||||||
} else {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.unblockOperation();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unblock operation if there's any blocked operation.
|
||||||
|
*/
|
||||||
|
protected unblockOperation(): void {
|
||||||
|
if (!this.formData.syncId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CoreSync.unblockOperation(AddonModForumProvider.COMPONENT, this.formData.syncId);
|
||||||
|
delete this.formData.syncId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scroll to reply/edit form.
|
||||||
|
*
|
||||||
|
* @param ticksToWait Number of ticks to wait before scrolling.
|
||||||
|
* @return Promise resolved when done.
|
||||||
|
*/
|
||||||
|
protected async scrollToForm(ticksToWait = 1): Promise<void> {
|
||||||
|
if (!this.content) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await CoreUtils.nextTicks(ticksToWait);
|
||||||
|
|
||||||
|
CoreDomUtils.scrollToElementBySelector(
|
||||||
|
this.elementRef.nativeElement,
|
||||||
|
this.content,
|
||||||
|
'#addon-forum-reply-edit-form-' + this.uniqueId,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,7 +93,7 @@
|
||||||
<addon-mod-forum-post
|
<addon-mod-forum-post
|
||||||
[post]="startingPost" [discussion]="discussion" [courseId]="courseId" [highlight]="true"
|
[post]="startingPost" [discussion]="discussion" [courseId]="courseId" [highlight]="true"
|
||||||
[discussionId]="discussionId" [component]="component" [componentId]="cmId"
|
[discussionId]="discussionId" [component]="component" [componentId]="cmId"
|
||||||
[replyData]="replyData" [originalData]="originalData" [forum]="forum" [accessInfo]="accessInfo"
|
[formData]="formData" [originalData]="originalData" [forum]="forum" [accessInfo]="accessInfo"
|
||||||
[trackPosts]="trackPosts" [ratingInfo]="ratingInfo" [leavingPage]="leavingPage"
|
[trackPosts]="trackPosts" [ratingInfo]="ratingInfo" [leavingPage]="leavingPage"
|
||||||
(onPostChange)="postListChanged()">
|
(onPostChange)="postListChanged()">
|
||||||
</addon-mod-forum-post>
|
</addon-mod-forum-post>
|
||||||
|
@ -104,7 +104,7 @@
|
||||||
<core-spacer *ngIf="!first"></core-spacer>
|
<core-spacer *ngIf="!first"></core-spacer>
|
||||||
<addon-mod-forum-post
|
<addon-mod-forum-post
|
||||||
[post]="post" [courseId]="courseId" [discussionId]="discussionId"
|
[post]="post" [courseId]="courseId" [discussionId]="discussionId"
|
||||||
[component]="component" [componentId]="cmId" [replyData]="replyData"
|
[component]="component" [componentId]="cmId" [formData]="formData"
|
||||||
[originalData]="originalData" [parentSubject]="postSubjects[post.parentid]"
|
[originalData]="originalData" [parentSubject]="postSubjects[post.parentid]"
|
||||||
[forum]="forum" [accessInfo]="accessInfo" [trackPosts]="trackPosts" [ratingInfo]="ratingInfo"
|
[forum]="forum" [accessInfo]="accessInfo" [trackPosts]="trackPosts" [ratingInfo]="ratingInfo"
|
||||||
[leavingPage]="leavingPage"
|
[leavingPage]="leavingPage"
|
||||||
|
@ -123,7 +123,7 @@
|
||||||
<ion-card>
|
<ion-card>
|
||||||
<addon-mod-forum-post
|
<addon-mod-forum-post
|
||||||
[post]="post" [courseId]="courseId" [discussionId]="discussionId" [component]="component"
|
[post]="post" [courseId]="courseId" [discussionId]="discussionId" [component]="component"
|
||||||
[componentId]="cmId" [replyData]="replyData" [originalData]="originalData"
|
[componentId]="cmId" [formData]="formData" [originalData]="originalData"
|
||||||
[parentSubject]="postSubjects[post.parentid]" [forum]="forum" [accessInfo]="accessInfo"
|
[parentSubject]="postSubjects[post.parentid]" [forum]="forum" [accessInfo]="accessInfo"
|
||||||
[trackPosts]="trackPosts" [ratingInfo]="ratingInfo" [leavingPage]="leavingPage"
|
[trackPosts]="trackPosts" [ratingInfo]="ratingInfo" [leavingPage]="leavingPage"
|
||||||
(onPostChange)="postListChanged()">
|
(onPostChange)="postListChanged()">
|
||||||
|
|
|
@ -39,7 +39,7 @@ import {
|
||||||
AddonModForumDiscussion,
|
AddonModForumDiscussion,
|
||||||
AddonModForumPost,
|
AddonModForumPost,
|
||||||
AddonModForumProvider,
|
AddonModForumProvider,
|
||||||
AddonModForumReply,
|
AddonModForumPostFormData,
|
||||||
} from '../../services/forum';
|
} from '../../services/forum';
|
||||||
import { AddonModForumHelper } from '../../services/forum-helper';
|
import { AddonModForumHelper } from '../../services/forum-helper';
|
||||||
import { AddonModForumOffline } from '../../services/forum-offline';
|
import { AddonModForumOffline } from '../../services/forum-offline';
|
||||||
|
@ -74,7 +74,7 @@ export class AddonModForumDiscussionPage implements OnInit, AfterViewInit, OnDes
|
||||||
postHasOffline!: boolean;
|
postHasOffline!: boolean;
|
||||||
sort: SortType = 'nested';
|
sort: SortType = 'nested';
|
||||||
trackPosts!: boolean;
|
trackPosts!: boolean;
|
||||||
replyData: Omit<AddonModForumReply, 'id'> = {
|
formData: AddonModForumSharedPostFormData = {
|
||||||
replyingTo: 0,
|
replyingTo: 0,
|
||||||
isEditing: false,
|
isEditing: false,
|
||||||
subject: '',
|
subject: '',
|
||||||
|
@ -83,7 +83,7 @@ export class AddonModForumDiscussionPage implements OnInit, AfterViewInit, OnDes
|
||||||
isprivatereply: false,
|
isprivatereply: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
originalData: Omit<AddonModForumReply, 'id'> = {
|
originalData: Omit<AddonModForumPostFormData, 'id'> = {
|
||||||
subject: null,
|
subject: null,
|
||||||
message: null,
|
message: null,
|
||||||
files: [],
|
files: [],
|
||||||
|
@ -259,13 +259,13 @@ export class AddonModForumDiscussionPage implements OnInit, AfterViewInit, OnDes
|
||||||
* @return Resolved if we can leave it, rejected if not.
|
* @return Resolved if we can leave it, rejected if not.
|
||||||
*/
|
*/
|
||||||
async canLeave(): Promise<boolean> {
|
async canLeave(): Promise<boolean> {
|
||||||
if (AddonModForumHelper.hasPostDataChanged(this.replyData, this.originalData)) {
|
if (AddonModForumHelper.hasPostDataChanged(this.formData, this.originalData)) {
|
||||||
// Show confirmation if some data has been modified.
|
// Show confirmation if some data has been modified.
|
||||||
await CoreDomUtils.showConfirm(Translate.instant('core.confirmcanceledit'));
|
await CoreDomUtils.showConfirm(Translate.instant('core.confirmcanceledit'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete the local files from the tmp folder.
|
// Delete the local files from the tmp folder.
|
||||||
CoreFileUploader.clearTmpFiles(this.replyData.files);
|
CoreFileUploader.clearTmpFiles(this.formData.files);
|
||||||
|
|
||||||
this.leavingPage = true;
|
this.leavingPage = true;
|
||||||
|
|
||||||
|
@ -795,3 +795,11 @@ export class AddonModForumDiscussionPage implements OnInit, AfterViewInit, OnDes
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reply data shared by post.
|
||||||
|
*/
|
||||||
|
export type AddonModForumSharedPostFormData = Omit<AddonModForumPostFormData, 'id'> & {
|
||||||
|
id?: number; // ID when editing an online reply.
|
||||||
|
syncId?: string; // Sync ID if some post has blocked synchronization.
|
||||||
|
};
|
||||||
|
|
|
@ -1559,9 +1559,9 @@ export type AddonModForumAccessInformation = {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reply info.
|
* Post creation or edition data.
|
||||||
*/
|
*/
|
||||||
export type AddonModForumReply = {
|
export type AddonModForumPostFormData = {
|
||||||
id: number;
|
id: number;
|
||||||
subject: string | null; // Null means original data is not set.
|
subject: string | null; // Null means original data is not set.
|
||||||
message: string | null; // Null means empty or just white space.
|
message: string | null; // Null means empty or just white space.
|
||||||
|
|
|
@ -1728,12 +1728,12 @@ export class CoreDomUtilsProvider {
|
||||||
/**
|
/**
|
||||||
* Opens a popover.
|
* Opens a popover.
|
||||||
*
|
*
|
||||||
* @param popoverOptions Modal Options.
|
* @param options Options.
|
||||||
|
* @return Promise resolved when the popover is dismissed or will be dismissed.
|
||||||
*/
|
*/
|
||||||
async openPopover<T = void>(
|
async openPopover<T = void>(options: OpenPopoverOptions): Promise<T | undefined> {
|
||||||
popoverOptions: PopoverOptions,
|
|
||||||
): Promise<T | undefined> {
|
|
||||||
|
|
||||||
|
const { waitForDismissCompleted, ...popoverOptions } = options;
|
||||||
const popover = await PopoverController.create(popoverOptions);
|
const popover = await PopoverController.create(popoverOptions);
|
||||||
const zoomLevel = await CoreConfig.get(CoreConstants.SETTINGS_ZOOM_LEVEL, CoreZoomLevel.NORMAL);
|
const zoomLevel = await CoreConfig.get(CoreConstants.SETTINGS_ZOOM_LEVEL, CoreZoomLevel.NORMAL);
|
||||||
|
|
||||||
|
@ -1743,16 +1743,15 @@ export class CoreDomUtilsProvider {
|
||||||
if (zoomLevel !== CoreZoomLevel.NORMAL) {
|
if (zoomLevel !== CoreZoomLevel.NORMAL) {
|
||||||
switch (getMode()) {
|
switch (getMode()) {
|
||||||
case 'ios':
|
case 'ios':
|
||||||
fixIOSPopoverPosition(popover, popoverOptions.event);
|
fixIOSPopoverPosition(popover, options.event);
|
||||||
break;
|
break;
|
||||||
case 'md':
|
case 'md':
|
||||||
fixMDPopoverPosition(popover, popoverOptions.event);
|
fixMDPopoverPosition(popover, options.event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If onDidDismiss is nedded we can add a new param to the function to wait one function or the other.
|
const result = waitForDismissCompleted ? await popover.onDidDismiss<T>() : await popover.onWillDismiss<T>();
|
||||||
const result = await popover.onWillDismiss<T>();
|
|
||||||
if (result?.data) {
|
if (result?.data) {
|
||||||
return result?.data;
|
return result?.data;
|
||||||
}
|
}
|
||||||
|
@ -2046,3 +2045,10 @@ export const CoreDomUtils = makeSingleton(CoreDomUtilsProvider);
|
||||||
|
|
||||||
type AnchorOrMediaElement =
|
type AnchorOrMediaElement =
|
||||||
HTMLAnchorElement | HTMLImageElement | HTMLAudioElement | HTMLVideoElement | HTMLSourceElement | HTMLTrackElement;
|
HTMLAnchorElement | HTMLImageElement | HTMLAudioElement | HTMLVideoElement | HTMLSourceElement | HTMLTrackElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options for the openPopover function.
|
||||||
|
*/
|
||||||
|
export type OpenPopoverOptions = PopoverOptions & {
|
||||||
|
waitForDismissCompleted?: boolean;
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in New Issue