import { t } from "../../services/i18n.js"; import BasicWidget from "../basic_widget.js"; import server from "../../services/server.js"; import dialogService from "../../services/dialog.js"; import toastService from "../../services/toast.js"; import ws from "../../services/ws.js"; import appContext from "../../components/app_context.js"; import openService from "../../services/open.js"; import utils from "../../services/utils.js"; import { Dropdown } from "bootstrap"; import type FAttachment from "../../entities/fattachment.js"; import type AttachmentDetailWidget from "../attachment_detail.js"; import type { NoteRow } from "@triliumnext/commons"; const TPL = /*html*/` `; // TODO: Deduplicate interface AttachmentResponse { note: NoteRow; } export default class AttachmentActionsWidget extends BasicWidget { $uploadNewRevisionInput!: JQuery; attachment: FAttachment; isFullDetail: boolean; dropdown!: Dropdown; constructor(attachment: FAttachment, isFullDetail: boolean) { super(); this.attachment = attachment; this.isFullDetail = isFullDetail; } get attachmentId() { return this.attachment.attachmentId; } doRender() { this.$widget = $(TPL); this.dropdown = Dropdown.getOrCreateInstance(this.$widget.find("[data-bs-toggle='dropdown']")[0]); this.$widget.on("click", ".dropdown-item", () => this.dropdown.toggle()); this.$uploadNewRevisionInput = this.$widget.find(".attachment-upload-new-revision-input"); this.$uploadNewRevisionInput.on("change", async () => { const fileToUpload = this.$uploadNewRevisionInput[0].files?.item(0); // copy to allow reset below this.$uploadNewRevisionInput.val(""); if (fileToUpload) { const result = await server.upload(`attachments/${this.attachmentId}/file`, fileToUpload); if (result.uploaded) { toastService.showMessage(t("attachments_actions.upload_success")); } else { toastService.showError(t("attachments_actions.upload_failed")); } } }); const isElectron = utils.isElectron(); if (!this.isFullDetail) { const $openAttachmentButton = this.$widget.find("[data-trigger-command='openAttachment']"); $openAttachmentButton.addClass("disabled").append($('').attr("title", t("attachments_actions.open_externally_detail_page"))); if (isElectron) { const $openAttachmentCustomButton = this.$widget.find("[data-trigger-command='openAttachmentCustom']"); $openAttachmentCustomButton.addClass("disabled").append($('').attr("title", t("attachments_actions.open_externally_detail_page"))); } } if (!isElectron) { const $openAttachmentCustomButton = this.$widget.find("[data-trigger-command='openAttachmentCustom']"); $openAttachmentCustomButton.addClass("disabled").append($('').attr("title", t("attachments_actions.open_custom_client_only"))); } } async openAttachmentCommand() { await openService.openAttachmentExternally(this.attachmentId, this.attachment.mime); } async openAttachmentCustomCommand() { await openService.openAttachmentCustom(this.attachmentId, this.attachment.mime); } async downloadAttachmentCommand() { await openService.downloadAttachment(this.attachmentId); } async uploadNewAttachmentRevisionCommand() { this.$uploadNewRevisionInput.trigger("click"); } async copyAttachmentLinkToClipboardCommand() { if (this.parent && "copyAttachmentLinkToClipboard" in this.parent) { (this.parent as AttachmentDetailWidget).copyAttachmentLinkToClipboard(); } } async deleteAttachmentCommand() { if (!(await dialogService.confirm(t("attachments_actions.delete_confirm", { title: this.attachment.title })))) { return; } await server.remove(`attachments/${this.attachmentId}`); toastService.showMessage(t("attachments_actions.delete_success", { title: this.attachment.title })); } async convertAttachmentIntoNoteCommand() { if (!(await dialogService.confirm(t("attachments_actions.convert_confirm", { title: this.attachment.title })))) { return; } const { note: newNote } = await server.post(`attachments/${this.attachmentId}/convert-to-note`); toastService.showMessage(t("attachments_actions.convert_success", { title: this.attachment.title })); await ws.waitForMaxKnownEntityChangeId(); await appContext.tabManager.getActiveContext()?.setNote(newNote.noteId); } async renameAttachmentCommand() { const attachmentTitle = await dialogService.prompt({ title: t("attachments_actions.rename_attachment"), message: t("attachments_actions.enter_new_name"), defaultValue: this.attachment.title }); if (!attachmentTitle?.trim()) { return; } await server.put(`attachments/${this.attachmentId}/rename`, { title: attachmentTitle }); } }