Notes/src/public/app/widgets/buttons/note_actions.ts

253 lines
10 KiB
TypeScript
Raw Normal View History

2021-05-24 22:29:49 +02:00
import NoteContextAwareWidget from "../note_context_aware_widget.js";
import utils from "../../services/utils.js";
import branchService from "../../services/branches.js";
import dialogService from "../../services/dialog.js";
import server from "../../services/server.js";
import toastService from "../../services/toast.js";
import ws from "../../services/ws.js";
2025-01-31 21:08:09 +02:00
import appContext, { type EventData } from "../../components/app_context.js";
import { t } from "../../services/i18n.js";
2025-01-31 21:08:09 +02:00
import type FNote from "../../entities/fnote.js";
import type { FAttachmentRow } from "../../entities/fattachment.js";
// TODO: Deduplicate with server
interface ConvertToAttachmentResponse {
attachment: FAttachmentRow;
}
2020-01-19 13:19:40 +01:00
const TPL = /*html*/`
2020-01-19 13:19:40 +01:00
<div class="dropdown note-actions">
2024-11-19 14:03:30 +08:00
<style>
.note-actions {
width: 35px;
height: 35px;
}
2024-11-19 11:08:20 +08:00
2024-11-19 14:03:30 +08:00
.note-actions .dropdown-menu {
min-width: 15em;
}
2024-11-19 11:08:20 +08:00
2024-11-19 14:03:30 +08:00
.note-actions .dropdown-item .bx {
position: relative;
top: 3px;
font-size: 120%;
margin-right: 5px;
}
2024-11-19 11:08:20 +08:00
2024-11-19 14:03:30 +08:00
.note-actions .dropdown-item[disabled], .note-actions .dropdown-item[disabled]:hover {
color: var(--muted-text-color) !important;
background-color: transparent !important;
pointer-events: none; /* makes it unclickable */
}
2020-02-27 00:58:10 +01:00
2024-11-19 14:03:30 +08:00
</style>
2024-11-19 11:08:20 +08:00
2024-11-19 14:03:30 +08:00
<button type="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"
class="icon-action bx bx-dots-vertical-rounded"></button>
2021-05-18 22:49:47 +02:00
2024-11-19 14:03:30 +08:00
<div class="dropdown-menu dropdown-menu-right">
<li data-trigger-command="convertNoteIntoAttachment" class="dropdown-item">
2025-01-09 18:07:02 +02:00
<span class="bx bx-paperclip"></span> ${t("note_actions.convert_into_attachment")}
2024-11-19 14:03:30 +08:00
</li>
2025-01-20 18:45:56 +02:00
2024-11-19 14:03:30 +08:00
<li data-trigger-command="renderActiveNote" class="dropdown-item render-note-button">
2025-01-09 18:07:02 +02:00
<span class="bx bx-extension"></span> ${t("note_actions.re_render_note")}<kbd data-command="renderActiveNote"></kbd>
2024-11-19 14:03:30 +08:00
</li>
2024-11-19 23:32:10 +02:00
2024-11-19 14:03:30 +08:00
<li data-trigger-command="findInText" class="dropdown-item find-in-text-button">
2025-01-09 18:07:02 +02:00
<span class='bx bx-search'></span> ${t("note_actions.search_in_note")}<kbd data-command="findInText"></kbd>
2024-11-19 14:03:30 +08:00
</li>
2024-11-19 23:32:10 +02:00
<li data-trigger-command="printActiveNote" class="dropdown-item print-active-note-button">
<span class="bx bx-printer"></span> ${t("note_actions.print_note")}<kbd data-command="printActiveNote"></kbd>
</li>
2024-11-19 23:32:10 +02:00
<li data-trigger-command="exportAsPdf" class="dropdown-item export-as-pdf-button">
2025-01-31 22:01:44 +02:00
<span class="bx bxs-file-pdf"></span> ${t("note_actions.print_pdf")}<kbd data-command="exportAsPdf"></kbd>
</li>
2025-01-20 18:45:56 +02:00
2024-11-19 23:32:10 +02:00
<div class="dropdown-divider"></div>
2025-01-20 18:45:56 +02:00
2025-01-09 18:07:02 +02:00
<li class="dropdown-item import-files-button"><span class="bx bx-import"></span> ${t("note_actions.import_files")}</li>
2024-11-19 23:32:10 +02:00
2025-01-09 18:07:02 +02:00
<li class="dropdown-item export-note-button"><span class="bx bx-export"></span> ${t("note_actions.export_note")}</li>
2024-11-19 23:32:10 +02:00
2025-01-20 18:45:56 +02:00
2024-11-19 23:32:10 +02:00
<div class="dropdown-divider"></div>
2025-01-09 18:07:02 +02:00
<li data-trigger-command="openNoteExternally" class="dropdown-item open-note-externally-button" title="${t("note_actions.open_note_externally_title")}">
<span class="bx bx-file-find"></span> ${t("note_actions.open_note_externally")}<kbd data-command="openNoteExternally"></kbd>
2024-11-19 14:03:30 +08:00
</li>
2024-11-19 23:32:10 +02:00
2024-11-19 14:03:30 +08:00
<li data-trigger-command="openNoteCustom" class="dropdown-item open-note-custom-button">
2025-01-09 18:07:02 +02:00
<span class="bx bx-customize"></span> ${t("note_actions.open_note_custom")}<kbd data-command="openNoteCustom"></kbd>
2024-11-19 14:03:30 +08:00
</li>
2024-11-19 23:32:10 +02:00
<li data-trigger-command="showNoteSource" class="dropdown-item show-source-button">
2025-01-09 18:07:02 +02:00
<span class="bx bx-code"></span> ${t("note_actions.note_source")}<kbd data-command="showNoteSource"></kbd>
2024-11-19 23:32:10 +02:00
</li>
2025-01-20 18:45:56 +02:00
2024-11-19 23:32:10 +02:00
<div class="dropdown-divider"></div>
2024-11-19 14:03:30 +08:00
<li data-trigger-command="forceSaveRevision" class="dropdown-item save-revision-button">
2025-01-09 18:07:02 +02:00
<span class="bx bx-save"></span> ${t("note_actions.save_revision")}<kbd data-command="forceSaveRevision"></kbd>
2024-11-19 14:03:30 +08:00
</li>
2024-11-19 23:32:10 +02:00
2025-01-09 18:07:02 +02:00
<li class="dropdown-item delete-note-button"><span class="bx bx-trash destructive-action-icon"></span> ${t("note_actions.delete_note")}</li>
2024-11-19 23:32:10 +02:00
2025-01-20 18:45:56 +02:00
2024-11-19 23:32:10 +02:00
<div class="dropdown-divider"></div>
2025-01-20 18:45:56 +02:00
2024-11-19 23:32:10 +02:00
<li data-trigger-command="showAttachments" class="dropdown-item show-attachments-button">
2025-01-09 18:07:02 +02:00
<span class="bx bx-paperclip"></span> ${t("note_actions.note_attachments")}<kbd data-command="showAttachments"></kbd>
2024-11-19 23:32:10 +02:00
</li>
2024-11-19 14:03:30 +08:00
</div>
2020-01-19 13:19:40 +01:00
</div>`;
2021-05-22 12:35:41 +02:00
export default class NoteActionsWidget extends NoteContextAwareWidget {
2025-01-31 21:08:09 +02:00
private $convertNoteIntoAttachmentButton!: JQuery<HTMLElement>;
private $findInTextButton!: JQuery<HTMLElement>;
private $printActiveNoteButton!: JQuery<HTMLElement>;
private $exportAsPdfButton!: JQuery<HTMLElement>;
2025-01-31 21:08:09 +02:00
private $showSourceButton!: JQuery<HTMLElement>;
private $showAttachmentsButton!: JQuery<HTMLElement>;
private $renderNoteButton!: JQuery<HTMLElement>;
private $saveRevisionButton!: JQuery<HTMLElement>;
private $exportNoteButton!: JQuery<HTMLElement>;
private $importNoteButton!: JQuery<HTMLElement>;
private $openNoteExternallyButton!: JQuery<HTMLElement>;
private $openNoteCustomButton!: JQuery<HTMLElement>;
private $deleteNoteButton!: JQuery<HTMLElement>;
2021-09-30 13:02:07 +02:00
isEnabled() {
2025-01-09 18:07:02 +02:00
return this.note?.type !== "launcher";
2021-09-30 13:02:07 +02:00
}
2020-01-19 13:19:40 +01:00
doRender() {
this.$widget = $(TPL);
2025-01-31 21:08:09 +02:00
this.$widget.on("show.bs.dropdown", () => {
if (this.note) {
this.refreshVisibility(this.note);
}
});
2020-01-19 13:19:40 +01:00
this.$convertNoteIntoAttachmentButton = this.$widget.find("[data-trigger-command='convertNoteIntoAttachment']");
2025-01-09 18:07:02 +02:00
this.$findInTextButton = this.$widget.find(".find-in-text-button");
this.$printActiveNoteButton = this.$widget.find(".print-active-note-button");
this.$exportAsPdfButton = this.$widget.find(".export-as-pdf-button");
2025-01-09 18:07:02 +02:00
this.$showSourceButton = this.$widget.find(".show-source-button");
this.$showAttachmentsButton = this.$widget.find(".show-attachments-button");
this.$renderNoteButton = this.$widget.find(".render-note-button");
2024-08-17 01:57:52 +03:00
this.$saveRevisionButton = this.$widget.find(".save-revision-button");
2020-01-21 21:43:23 +01:00
2025-01-09 18:07:02 +02:00
this.$exportNoteButton = this.$widget.find(".export-note-button");
2020-01-21 21:43:23 +01:00
this.$exportNoteButton.on("click", () => {
2025-01-31 21:08:09 +02:00
if (this.$exportNoteButton.hasClass("disabled") || !this.noteContext?.notePath) {
2020-01-21 21:43:23 +01:00
return;
}
2022-06-16 15:04:57 +02:00
this.triggerCommand("showExportDialog", {
notePath: this.noteContext.notePath,
defaultType: "single"
});
2020-01-21 21:43:23 +01:00
});
2025-01-09 18:07:02 +02:00
this.$importNoteButton = this.$widget.find(".import-files-button");
2025-01-31 21:08:09 +02:00
this.$importNoteButton.on("click", () => {
if (this.noteId) {
this.triggerCommand("showImportDialog", { noteId: this.noteId });
}
});
2020-01-20 22:35:52 +01:00
2025-01-09 18:07:02 +02:00
this.$widget.on("click", ".dropdown-item", () => this.$widget.find("[data-bs-toggle='dropdown']").dropdown("toggle"));
this.$openNoteExternallyButton = this.$widget.find(".open-note-externally-button");
2023-05-16 11:57:28 +00:00
this.$openNoteCustomButton = this.$widget.find(".open-note-custom-button");
this.$deleteNoteButton = this.$widget.find(".delete-note-button");
this.$deleteNoteButton.on("click", () => {
2025-01-31 21:08:09 +02:00
if (!this.note || this.note.noteId === "root") {
return;
}
branchService.deleteNotes([this.note.getParentBranches()[0].branchId], true);
});
2020-01-19 13:19:40 +01:00
}
2020-01-20 22:35:52 +01:00
2025-01-31 21:08:09 +02:00
async refreshVisibility(note: FNote) {
const isInOptions = note.noteId.startsWith("_options");
this.$convertNoteIntoAttachmentButton.toggle(note.isEligibleForConversionToAttachment());
2025-01-09 18:07:02 +02:00
this.toggleDisabled(this.$findInTextButton, ["text", "code", "book"].includes(note.type));
this.toggleDisabled(this.$showAttachmentsButton, !isInOptions);
2025-01-20 18:45:56 +02:00
this.toggleDisabled(this.$showSourceButton, ["text", "code", "relationMap", "mermaid", "canvas", "mindMap", "geoMap"].includes(note.type));
const canPrint = ["text", "code"].includes(note.type);
this.toggleDisabled(this.$printActiveNoteButton, canPrint);
this.toggleDisabled(this.$exportAsPdfButton, canPrint);
this.$exportAsPdfButton.toggleClass("hidden-ext", !utils.isElectron());
2025-01-09 18:07:02 +02:00
this.$renderNoteButton.toggle(note.type === "render");
2020-03-25 11:28:44 +01:00
2025-01-09 18:07:02 +02:00
this.toggleDisabled(this.$openNoteExternallyButton, utils.isElectron() && !["search", "book"].includes(note.type));
this.toggleDisabled(
this.$openNoteCustomButton,
utils.isElectron() &&
!utils.isMac() && // no implementation for Mac yet
!["search", "book"].includes(note.type)
);
// I don't want to handle all special notes like this, but intuitively user might want to export content of backend log
2025-01-09 18:07:02 +02:00
this.toggleDisabled(this.$exportNoteButton, !["_backendLog"].includes(note.noteId) && !isInOptions);
2025-01-09 18:07:02 +02:00
this.toggleDisabled(this.$importNoteButton, !["search"].includes(note.type) && !isInOptions);
2024-08-17 01:57:52 +03:00
this.toggleDisabled(this.$deleteNoteButton, !isInOptions);
this.toggleDisabled(this.$saveRevisionButton, !isInOptions);
}
async convertNoteIntoAttachmentCommand() {
2025-01-31 21:08:09 +02:00
if (!this.note || !(await dialogService.confirm(t("note_actions.convert_into_attachment_prompt", { title: this.note.title })))) {
return;
}
2025-01-31 21:08:09 +02:00
const { attachment: newAttachment } = await server.post<ConvertToAttachmentResponse>(`notes/${this.noteId}/convert-to-attachment`);
if (!newAttachment) {
2024-10-20 02:06:08 +03:00
toastService.showMessage(t("note_actions.convert_into_attachment_failed", { title: this.note.title }));
return;
}
2024-10-20 02:06:08 +03:00
toastService.showMessage(t("note_actions.convert_into_attachment_successful", { title: newAttachment.title }));
await ws.waitForMaxKnownEntityChangeId();
2025-03-03 21:02:18 +01:00
await appContext.tabManager.getActiveContext()?.setNote(newAttachment.ownerId, {
viewScope: {
2025-01-09 18:07:02 +02:00
viewMode: "attachments",
attachmentId: newAttachment.attachmentId
}
});
}
2025-01-31 21:08:09 +02:00
toggleDisabled($el: JQuery<HTMLElement>, enable: boolean) {
if (enable) {
2025-01-09 18:07:02 +02:00
$el.removeAttr("disabled");
} else {
2025-01-09 18:07:02 +02:00
$el.attr("disabled", "disabled");
}
}
2025-01-31 21:08:09 +02:00
entitiesReloadedEvent({ loadResults }: EventData<"entitiesReloaded">) {
if (loadResults.isNoteReloaded(this.noteId)) {
this.refresh();
}
2020-01-20 22:35:52 +01:00
}
2020-07-03 22:27:45 +02:00
}