-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Expand file tree
/
Copy pathpage-comment.ts
More file actions
182 lines (151 loc) · 6.48 KB
/
page-comment.ts
File metadata and controls
182 lines (151 loc) · 6.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
import {Component} from './component';
import {getLoading, htmlToDom} from '../services/dom';
import {PageCommentReference} from "./page-comment-reference";
import {HttpError} from "../services/http";
import {SimpleWysiwygEditorInterface} from "../wysiwyg";
import {el} from "../wysiwyg/utils/dom";
export interface PageCommentReplyEventData {
id: string; // ID of comment being replied to
element: HTMLElement; // Container for comment replied to
}
export interface PageCommentArchiveEventData {
new_thread_dom: HTMLElement;
}
export class PageComment extends Component {
protected commentId!: string;
protected commentLocalId!: string;
protected deletedText!: string;
protected updatedText!: string;
protected archiveText!: string;
protected wysiwygEditor: SimpleWysiwygEditorInterface|null = null;
protected wysiwygTextDirection!: string;
protected container!: HTMLElement;
protected contentContainer!: HTMLElement;
protected form!: HTMLFormElement;
protected formCancel!: HTMLElement;
protected editButton!: HTMLElement;
protected deleteButton!: HTMLElement;
protected replyButton!: HTMLElement;
protected archiveButton!: HTMLElement;
protected input!: HTMLInputElement;
setup() {
// Options
this.commentId = this.$opts.commentId;
this.commentLocalId = this.$opts.commentLocalId;
this.deletedText = this.$opts.deletedText;
this.updatedText = this.$opts.updatedText;
this.archiveText = this.$opts.archiveText;
// Editor reference and text options
this.wysiwygTextDirection = this.$opts.wysiwygTextDirection;
// Element references
this.container = this.$el;
this.contentContainer = this.$refs.contentContainer;
this.form = this.$refs.form as HTMLFormElement;
this.formCancel = this.$refs.formCancel;
this.editButton = this.$refs.editButton;
this.deleteButton = this.$refs.deleteButton;
this.replyButton = this.$refs.replyButton;
this.archiveButton = this.$refs.archiveButton;
this.input = this.$refs.input as HTMLInputElement;
this.setupListeners();
}
protected setupListeners(): void {
if (this.replyButton) {
const data: PageCommentReplyEventData = {
id: this.commentLocalId,
element: this.container,
};
this.replyButton.addEventListener('click', () => this.$emit('reply', data));
}
if (this.editButton) {
this.editButton.addEventListener('click', this.startEdit.bind(this));
this.form.addEventListener('submit', this.update.bind(this));
this.formCancel.addEventListener('click', () => this.toggleEditMode(false));
}
if (this.deleteButton) {
this.deleteButton.addEventListener('click', this.delete.bind(this));
}
if (this.archiveButton) {
this.archiveButton.addEventListener('click', this.archive.bind(this));
}
}
protected toggleEditMode(show: boolean) : void {
this.contentContainer.toggleAttribute('hidden', show);
this.form.toggleAttribute('hidden', !show);
}
protected async startEdit(): Promise<void> {
this.toggleEditMode(true);
if (this.wysiwygEditor) {
this.wysiwygEditor.focus();
return;
}
type WysiwygModule = typeof import('../wysiwyg');
const wysiwygModule = (await window.importVersioned('wysiwyg')) as WysiwygModule;
const editorContent = this.input.value;
const container = el('div', {class: 'comment-editor-container'});
this.input.parentElement?.appendChild(container);
this.input.hidden = true;
this.wysiwygEditor = wysiwygModule.createBasicEditorInstance(container as HTMLElement, editorContent, {
darkMode: document.documentElement.classList.contains('dark-mode'),
textDirection: this.$opts.textDirection,
translations: (window as unknown as Record<string, Object>).editor_translations,
});
this.wysiwygEditor.focus();
}
protected async update(event: Event): Promise<void> {
event.preventDefault();
const loading = this.showLoading();
this.form.toggleAttribute('hidden', true);
const reqData = {
html: await this.wysiwygEditor?.getContentAsHtml() || '',
};
try {
const resp = await window.$http.put(`/comment/${this.commentId}`, reqData);
const newComment = htmlToDom(resp.data as string);
this.container.replaceWith(newComment);
window.$events.success(this.updatedText);
} catch (err) {
console.error(err);
if (err instanceof HttpError) {
window.$events.showValidationErrors(err);
}
this.form.toggleAttribute('hidden', false);
loading.remove();
}
}
protected async delete(): Promise<void> {
this.showLoading();
await window.$http.delete(`/comment/${this.commentId}`);
this.$emit('delete');
const branch = this.container.closest('.comment-branch');
if (branch instanceof HTMLElement) {
const refs = window.$components.allWithinElement<PageCommentReference>(branch, 'page-comment-reference');
for (const ref of refs) {
ref.hideMarker();
}
branch.remove();
}
window.$events.success(this.deletedText);
}
protected async archive(): Promise<void> {
this.showLoading();
const isArchived = this.archiveButton.dataset.isArchived === 'true';
const action = isArchived ? 'unarchive' : 'archive';
const response = await window.$http.put(`/comment/${this.commentId}/${action}`);
window.$events.success(this.archiveText);
const eventData: PageCommentArchiveEventData = {new_thread_dom: htmlToDom(response.data as string)};
this.$emit(action, eventData);
const branch = this.container.closest('.comment-branch') as HTMLElement;
const references = window.$components.allWithinElement<PageCommentReference>(branch, 'page-comment-reference');
for (const reference of references) {
reference.hideMarker();
}
branch.remove();
}
protected showLoading(): HTMLElement {
const loading = getLoading();
loading.classList.add('px-l');
this.container.append(loading);
return loading;
}
}