]> BookStack Code Mirror - bookstack/blob - resources/js/components/page-comments.js
Merge branch 'fix/oidc-logout' into development
[bookstack] / resources / js / components / page-comments.js
1 import {Component} from './component';
2 import {getLoading, htmlToDom} from '../services/dom';
3
4 export class PageComments extends Component {
5
6     setup() {
7         this.elem = this.$el;
8         this.pageId = Number(this.$opts.pageId);
9
10         // Element references
11         this.container = this.$refs.commentContainer;
12         this.commentCountBar = this.$refs.commentCountBar;
13         this.commentsTitle = this.$refs.commentsTitle;
14         this.addButtonContainer = this.$refs.addButtonContainer;
15         this.replyToRow = this.$refs.replyToRow;
16         this.formContainer = this.$refs.formContainer;
17         this.form = this.$refs.form;
18         this.formInput = this.$refs.formInput;
19         this.formReplyLink = this.$refs.formReplyLink;
20         this.addCommentButton = this.$refs.addCommentButton;
21         this.hideFormButton = this.$refs.hideFormButton;
22         this.removeReplyToButton = this.$refs.removeReplyToButton;
23
24         // Translations
25         this.createdText = this.$opts.createdText;
26         this.countText = this.$opts.countText;
27
28         // Internal State
29         this.parentId = null;
30         this.formReplyText = this.formReplyLink?.textContent || '';
31
32         this.setupListeners();
33     }
34
35     setupListeners() {
36         this.elem.addEventListener('page-comment-delete', () => {
37             this.updateCount();
38             this.hideForm();
39         });
40
41         this.elem.addEventListener('page-comment-reply', event => {
42             this.setReply(event.detail.id, event.detail.element);
43         });
44
45         if (this.form) {
46             this.removeReplyToButton.addEventListener('click', this.removeReplyTo.bind(this));
47             this.hideFormButton.addEventListener('click', this.hideForm.bind(this));
48             this.addCommentButton.addEventListener('click', this.showForm.bind(this));
49             this.form.addEventListener('submit', this.saveComment.bind(this));
50         }
51     }
52
53     saveComment(event) {
54         event.preventDefault();
55         event.stopPropagation();
56
57         const loading = getLoading();
58         loading.classList.add('px-l');
59         this.form.after(loading);
60         this.form.toggleAttribute('hidden', true);
61
62         const text = this.formInput.value;
63         const reqData = {
64             text,
65             parent_id: this.parentId || null,
66         };
67
68         window.$http.post(`/comment/${this.pageId}`, reqData).then(resp => {
69             const newElem = htmlToDom(resp.data);
70             this.formContainer.after(newElem);
71             window.$events.success(this.createdText);
72             this.hideForm();
73             this.updateCount();
74         }).catch(err => {
75             this.form.toggleAttribute('hidden', false);
76             window.$events.showValidationErrors(err);
77         });
78
79         this.form.toggleAttribute('hidden', false);
80         loading.remove();
81     }
82
83     updateCount() {
84         const count = this.getCommentCount();
85         this.commentsTitle.textContent = window.trans_plural(this.countText, count, {count});
86     }
87
88     resetForm() {
89         this.formInput.value = '';
90         this.parentId = null;
91         this.replyToRow.toggleAttribute('hidden', true);
92         this.container.append(this.formContainer);
93     }
94
95     showForm() {
96         this.formContainer.toggleAttribute('hidden', false);
97         this.addButtonContainer.toggleAttribute('hidden', true);
98         this.formContainer.scrollIntoView({behavior: 'smooth', block: 'nearest'});
99         setTimeout(() => {
100             this.formInput.focus();
101         }, 100);
102     }
103
104     hideForm() {
105         this.resetForm();
106         this.formContainer.toggleAttribute('hidden', true);
107         if (this.getCommentCount() > 0) {
108             this.elem.append(this.addButtonContainer);
109         } else {
110             this.commentCountBar.append(this.addButtonContainer);
111         }
112         this.addButtonContainer.toggleAttribute('hidden', false);
113     }
114
115     getCommentCount() {
116         return this.container.querySelectorAll('[component="page-comment"]').length;
117     }
118
119     setReply(commentLocalId, commentElement) {
120         const targetFormLocation = commentElement.closest('.comment-branch').querySelector('.comment-branch-children');
121         targetFormLocation.append(this.formContainer);
122         this.showForm();
123         this.parentId = commentLocalId;
124         this.replyToRow.toggleAttribute('hidden', false);
125         this.formReplyLink.textContent = this.formReplyText.replace('1234', this.parentId);
126         this.formReplyLink.href = `#comment${this.parentId}`;
127     }
128
129     removeReplyTo() {
130         this.parentId = null;
131         this.replyToRow.toggleAttribute('hidden', true);
132         this.container.append(this.formContainer);
133         this.showForm();
134     }
135
136 }