diff --git a/apps/client/src/widgets/attachment_detail.ts b/apps/client/src/widgets/attachment_detail.ts index 29a2bf9ae..7f15c9fa6 100644 --- a/apps/client/src/widgets/attachment_detail.ts +++ b/apps/client/src/widgets/attachment_detail.ts @@ -76,23 +76,4 @@ export default class AttachmentDetailWidget extends BasicWidget { this.$wrapper.find(".attachment-content-wrapper").append($renderedContent); } - async copyAttachmentLinkToClipboard() { - if (this.attachment.role === "image") { - imageService.copyImageReferenceToClipboard(this.$wrapper.find(".attachment-content-wrapper")); - } else if (this.attachment.role === "file") { - const $link = await linkService.createLink(this.attachment.ownerId, { - referenceLink: true, - viewScope: { - viewMode: "attachments", - attachmentId: this.attachment.attachmentId - } - }); - - utils.copyHtmlToClipboard($link[0].outerHTML); - - toastService.showMessage(t("attachment_detail_2.link_copied")); - } else { - throw new Error(t("attachment_detail_2.unrecognized_role", { role: this.attachment.role })); - } - } } diff --git a/apps/client/src/widgets/buttons/attachments_actions.ts b/apps/client/src/widgets/buttons/attachments_actions.ts deleted file mode 100644 index 280e318bd..000000000 --- a/apps/client/src/widgets/buttons/attachments_actions.ts +++ /dev/null @@ -1,133 +0,0 @@ -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")); - } - } - }); - } - - 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 }); - } -} diff --git a/apps/client/src/widgets/react/FormFileUpload.tsx b/apps/client/src/widgets/react/FormFileUpload.tsx index c43008b09..33f06b525 100644 --- a/apps/client/src/widgets/react/FormFileUpload.tsx +++ b/apps/client/src/widgets/react/FormFileUpload.tsx @@ -18,15 +18,18 @@ export default function FormFileUpload({ inputRef, name, onChange, multiple, hid name={name} type="file" class="form-control-file" - multiple={multiple} - onChange={e => onChange((e.target as HTMLInputElement).files)} /> + multiple={multiple} + onChange={e => { + onChange((e.target as HTMLInputElement).files); + e.currentTarget.value = ""; + }} /> ) } /** * Combination of a button with a hidden file upload field. - * + * * @param param the change listener for the file upload and the properties for the button. */ export function FormFileUploadButton({ onChange, ...buttonProps }: Omit & Pick) { @@ -39,10 +42,10 @@ export function FormFileUploadButton({ onChange, ...buttonProps }: Omit inputRef.current?.click()} />