DevPlace CI / test (push) Failing after 28m20s
Also streamline the top navigation: drop the Tools dropdown, make Quizzes and Battles icon-only entries, and remove the Workspace, Containers and Editor entry points from the project detail page.
136 lines
4.1 KiB
JavaScript
136 lines
4.1 KiB
JavaScript
// retoor <retoor@molodetz.nl>
|
|
|
|
import { OptimisticAction } from "./OptimisticAction.js";
|
|
|
|
export class NoteManager extends OptimisticAction {
|
|
constructor() {
|
|
super();
|
|
document.addEventListener("click", (event) => this.onClick(event));
|
|
}
|
|
|
|
onClick(event) {
|
|
const toggle = event.target.closest("[data-note-toggle]");
|
|
if (toggle) {
|
|
event.preventDefault();
|
|
this.toggle(toggle);
|
|
return;
|
|
}
|
|
const cancel = event.target.closest(".note-editor-cancel");
|
|
if (cancel) {
|
|
event.preventDefault();
|
|
this.cancel(cancel);
|
|
return;
|
|
}
|
|
const save = event.target.closest(".note-editor-save");
|
|
if (save) {
|
|
event.preventDefault();
|
|
this.save(save);
|
|
return;
|
|
}
|
|
const remove = event.target.closest(".note-editor-delete");
|
|
if (remove) {
|
|
event.preventDefault();
|
|
this.remove(remove);
|
|
}
|
|
}
|
|
|
|
toggle(button) {
|
|
const widget = button.closest(".note-widget");
|
|
const editor = widget ? widget.querySelector(".note-editor") : null;
|
|
if (!editor) {
|
|
return;
|
|
}
|
|
const opening = editor.hidden;
|
|
editor.hidden = !opening;
|
|
button.setAttribute("aria-expanded", opening ? "true" : "false");
|
|
if (opening) {
|
|
const textarea = editor.querySelector(".note-editor-textarea");
|
|
if (textarea) {
|
|
textarea.focus();
|
|
}
|
|
}
|
|
}
|
|
|
|
cancel(button) {
|
|
const widget = button.closest(".note-widget");
|
|
const editor = widget ? widget.querySelector(".note-editor") : null;
|
|
const toggle = widget ? widget.querySelector("[data-note-toggle]") : null;
|
|
if (!editor) {
|
|
return;
|
|
}
|
|
const textarea = editor.querySelector(".note-editor-textarea");
|
|
if (textarea) {
|
|
textarea.value = textarea.dataset.saved || "";
|
|
}
|
|
editor.hidden = true;
|
|
if (toggle) {
|
|
toggle.setAttribute("aria-expanded", "false");
|
|
}
|
|
}
|
|
|
|
async save(button) {
|
|
const widget = button.closest(".note-widget");
|
|
const editor = widget ? widget.querySelector(".note-editor") : null;
|
|
const textarea = editor ? editor.querySelector(".note-editor-textarea") : null;
|
|
if (!widget || !textarea) {
|
|
return;
|
|
}
|
|
const content = textarea.value.trim();
|
|
if (!content) {
|
|
return;
|
|
}
|
|
const type = widget.dataset.noteType;
|
|
const uid = widget.dataset.noteUid;
|
|
await this.submit(
|
|
`/notes/${type}/${uid}`,
|
|
{ content },
|
|
widget,
|
|
(result) => this.applySaved(widget, result.content),
|
|
button
|
|
);
|
|
}
|
|
|
|
async remove(button) {
|
|
const widget = button.closest(".note-widget");
|
|
if (!widget) {
|
|
return;
|
|
}
|
|
const type = widget.dataset.noteType;
|
|
const uid = widget.dataset.noteUid;
|
|
await this.submit(
|
|
`/notes/${type}/${uid}/delete`,
|
|
{},
|
|
widget,
|
|
() => this.applySaved(widget, ""),
|
|
button
|
|
);
|
|
}
|
|
|
|
applySaved(widget, content) {
|
|
const toggle = widget.querySelector("[data-note-toggle]");
|
|
const editor = widget.querySelector(".note-editor");
|
|
const textarea = editor ? editor.querySelector(".note-editor-textarea") : null;
|
|
const label = toggle ? toggle.querySelector(".note-label") : null;
|
|
const deleteBtn = editor ? editor.querySelector(".note-editor-delete") : null;
|
|
if (textarea) {
|
|
textarea.value = content;
|
|
textarea.dataset.saved = content;
|
|
}
|
|
if (toggle) {
|
|
toggle.classList.toggle("has-note", Boolean(content));
|
|
}
|
|
if (label) {
|
|
label.textContent = content ? "Edit note" : "Add note";
|
|
}
|
|
if (deleteBtn) {
|
|
deleteBtn.hidden = !content;
|
|
}
|
|
if (editor) {
|
|
editor.hidden = true;
|
|
}
|
|
if (toggle) {
|
|
toggle.setAttribute("aria-expanded", "false");
|
|
}
|
|
}
|
|
}
|