1
0
mirror of https://github.com/BookStackApp/BookStack.git synced 2025-06-08 15:21:56 +03:00
bookstack/resources/js/components/page-comment.ts
Dan Brown e8f44186a8
Comments: Split out page comment reference logic to own component
Started support for editor view.
Moved comment elements to be added relative to content area instad of
specific target reference element.
Added relocating on screen size change.
2025-04-27 16:51:24 +01:00

136 lines
4.5 KiB
TypeScript

import {Component} from './component';
import {getLoading, htmlToDom} from '../services/dom.ts';
import {buildForInput} from '../wysiwyg-tinymce/config';
export class PageComment extends Component {
protected commentId: string;
protected commentLocalId: string;
protected deletedText: string;
protected updatedText: string;
protected wysiwygEditor: any = null;
protected wysiwygLanguage: string;
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 input: HTMLInputElement;
setup() {
// Options
this.commentId = this.$opts.commentId;
this.commentLocalId = this.$opts.commentLocalId;
this.deletedText = this.$opts.deletedText;
this.updatedText = this.$opts.updatedText;
// Editor reference and text options
this.wysiwygLanguage = this.$opts.wysiwygLanguage;
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.input = this.$refs.input as HTMLInputElement;
this.setupListeners();
}
protected setupListeners(): void {
if (this.replyButton) {
this.replyButton.addEventListener('click', () => this.$emit('reply', {
id: this.commentLocalId,
element: this.container,
}));
}
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));
}
}
protected toggleEditMode(show: boolean) : void {
this.contentContainer.toggleAttribute('hidden', show);
this.form.toggleAttribute('hidden', !show);
}
protected startEdit() : void {
this.toggleEditMode(true);
if (this.wysiwygEditor) {
this.wysiwygEditor.focus();
return;
}
const config = buildForInput({
language: this.wysiwygLanguage,
containerElement: this.input,
darkMode: document.documentElement.classList.contains('dark-mode'),
textDirection: this.wysiwygTextDirection,
drawioUrl: '',
pageId: 0,
translations: {},
translationMap: (window as Record<string, Object>).editor_translations,
});
(window as {tinymce: {init: (Object) => Promise<any>}}).tinymce.init(config).then(editors => {
this.wysiwygEditor = editors[0];
setTimeout(() => this.wysiwygEditor.focus(), 50);
});
}
protected async update(event: Event): Promise<void> {
event.preventDefault();
const loading = this.showLoading();
this.form.toggleAttribute('hidden', true);
const reqData = {
html: this.wysiwygEditor.getContent(),
};
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);
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');
this.container.closest('.comment-branch')?.remove();
window.$events.success(this.deletedText);
}
protected showLoading(): HTMLElement {
const loading = getLoading();
loading.classList.add('px-l');
this.container.append(loading);
return loading;
}
}