]> BookStack Code Mirror - bookstack/blob - resources/js/components/page-comments.js
JS: Converted/updated translation code to TS, fixed some comment counts
[bookstack] / resources / js / components / page-comments.js
1 import {Component} from './component';
2 import {getLoading, htmlToDom} from '../services/dom';
3 import {buildForInput} from '../wysiwyg-tinymce/config';
4
5 export class PageComments extends Component {
6
7     setup() {
8         this.elem = this.$el;
9         this.pageId = Number(this.$opts.pageId);
10
11         // Element references
12         this.container = this.$refs.commentContainer;
13         this.commentCountBar = this.$refs.commentCountBar;
14         this.commentsTitle = this.$refs.commentsTitle;
15         this.addButtonContainer = this.$refs.addButtonContainer;
16         this.replyToRow = this.$refs.replyToRow;
17         this.formContainer = this.$refs.formContainer;
18         this.form = this.$refs.form;
19         this.formInput = this.$refs.formInput;
20         this.formReplyLink = this.$refs.formReplyLink;
21         this.addCommentButton = this.$refs.addCommentButton;
22         this.hideFormButton = this.$refs.hideFormButton;
23         this.removeReplyToButton = this.$refs.removeReplyToButton;
24
25         // WYSIWYG options
26         this.wysiwygLanguage = this.$opts.wysiwygLanguage;
27         this.wysiwygTextDirection = this.$opts.wysiwygTextDirection;
28         this.wysiwygEditor = null;
29
30         // Translations
31         this.createdText = this.$opts.createdText;
32         this.countText = this.$opts.countText;
33
34         // Internal State
35         this.parentId = null;
36         this.formReplyText = this.formReplyLink?.textContent || '';
37
38         this.setupListeners();
39     }
40
41     setupListeners() {
42         this.elem.addEventListener('page-comment-delete', () => {
43             setTimeout(() => this.updateCount(), 1);
44             this.hideForm();
45         });
46
47         this.elem.addEventListener('page-comment-reply', event => {
48             this.setReply(event.detail.id, event.detail.element);
49         });
50
51         if (this.form) {
52             this.removeReplyToButton.addEventListener('click', this.removeReplyTo.bind(this));
53             this.hideFormButton.addEventListener('click', this.hideForm.bind(this));
54             this.addCommentButton.addEventListener('click', this.showForm.bind(this));
55             this.form.addEventListener('submit', this.saveComment.bind(this));
56         }
57     }
58
59     saveComment(event) {
60         event.preventDefault();
61         event.stopPropagation();
62
63         const loading = getLoading();
64         loading.classList.add('px-l');
65         this.form.after(loading);
66         this.form.toggleAttribute('hidden', true);
67
68         const reqData = {
69             html: this.wysiwygEditor.getContent(),
70             parent_id: this.parentId || null,
71         };
72
73         window.$http.post(`/comment/${this.pageId}`, reqData).then(resp => {
74             const newElem = htmlToDom(resp.data);
75
76             if (reqData.parent_id) {
77                 this.formContainer.after(newElem);
78             } else {
79                 this.container.append(newElem);
80             }
81
82             window.$events.success(this.createdText);
83             this.hideForm();
84             this.updateCount();
85         }).catch(err => {
86             this.form.toggleAttribute('hidden', false);
87             window.$events.showValidationErrors(err);
88         });
89
90         this.form.toggleAttribute('hidden', false);
91         loading.remove();
92     }
93
94     updateCount() {
95         const count = this.getCommentCount();
96         console.log('update count', count, this.container);
97         this.commentsTitle.textContent = window.$trans.choice(this.countText, count, {count});
98     }
99
100     resetForm() {
101         this.removeEditor();
102         this.formInput.value = '';
103         this.parentId = null;
104         this.replyToRow.toggleAttribute('hidden', true);
105         this.container.append(this.formContainer);
106     }
107
108     showForm() {
109         this.removeEditor();
110         this.formContainer.toggleAttribute('hidden', false);
111         this.addButtonContainer.toggleAttribute('hidden', true);
112         this.formContainer.scrollIntoView({behavior: 'smooth', block: 'nearest'});
113         this.loadEditor();
114     }
115
116     hideForm() {
117         this.resetForm();
118         this.formContainer.toggleAttribute('hidden', true);
119         if (this.getCommentCount() > 0) {
120             this.elem.append(this.addButtonContainer);
121         } else {
122             this.commentCountBar.append(this.addButtonContainer);
123         }
124         this.addButtonContainer.toggleAttribute('hidden', false);
125     }
126
127     loadEditor() {
128         if (this.wysiwygEditor) {
129             this.wysiwygEditor.focus();
130             return;
131         }
132
133         const config = buildForInput({
134             language: this.wysiwygLanguage,
135             containerElement: this.formInput,
136             darkMode: document.documentElement.classList.contains('dark-mode'),
137             textDirection: this.wysiwygTextDirection,
138             translations: {},
139             translationMap: window.editor_translations,
140         });
141
142         window.tinymce.init(config).then(editors => {
143             this.wysiwygEditor = editors[0];
144             setTimeout(() => this.wysiwygEditor.focus(), 50);
145         });
146     }
147
148     removeEditor() {
149         if (this.wysiwygEditor) {
150             this.wysiwygEditor.remove();
151             this.wysiwygEditor = null;
152         }
153     }
154
155     getCommentCount() {
156         return this.container.querySelectorAll('[component="page-comment"]').length;
157     }
158
159     setReply(commentLocalId, commentElement) {
160         const targetFormLocation = commentElement.closest('.comment-branch').querySelector('.comment-branch-children');
161         targetFormLocation.append(this.formContainer);
162         this.showForm();
163         this.parentId = commentLocalId;
164         this.replyToRow.toggleAttribute('hidden', false);
165         this.formReplyLink.textContent = this.formReplyText.replace('1234', this.parentId);
166         this.formReplyLink.href = `#comment${this.parentId}`;
167     }
168
169     removeReplyTo() {
170         this.parentId = null;
171         this.replyToRow.toggleAttribute('hidden', true);
172         this.container.append(this.formContainer);
173         this.showForm();
174     }
175
176 }