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