From f5475bfde6479aac9e4c07f7dee399a582a62c70 Mon Sep 17 00:00:00 2001 From: zsviczian Date: Mon, 20 Jan 2025 22:40:27 +0100 Subject: [PATCH] imagepath hook --- src/constants/assets/startupScript.md | 35 +++++++++++++++++++++++++++ src/constants/starutpscript.ts | 4 ++- src/shared/ExcalidrawAutomate.ts | 34 ++++++++++++++++++++++++++ src/shared/ExcalidrawData.ts | 28 ++++++++++++++------- src/view/ExcalidrawView.ts | 2 +- 5 files changed, 92 insertions(+), 11 deletions(-) diff --git a/src/constants/assets/startupScript.md b/src/constants/assets/startupScript.md index ce04eb7..8bace30 100644 --- a/src/constants/assets/startupScript.md +++ b/src/constants/assets/startupScript.md @@ -105,6 +105,41 @@ */ //ea.onFileCreateHook = (data) => {}; +/** + * If set, this callback is triggered when a image is being saved in Excalidraw. + * You can use this callback to customize the naming and path of pasted images to avoid + * default names like "Pasted image 123147170.png" being saved in the attachments folder, + * and instead use more meaningful names based on the Excalidraw file or other criteria, + * plus save the image in a different folder. + * + * If the function returns null or undefined, the normal Excalidraw operation will continue + * with the excalidraw generated name and default path. + * If a filepath is returned, that will be used. Include the full Vault filepath and filename + * with the file extension. + * The currentImageName is the name of the image generated by excalidraw or provided during paste. + * + * @param data - An object containing the following properties: + * @property {string} [currentImageName] - Default name for the image. + * @property {string} drawingFilePath - The file path of the Excalidraw file where the image is being used. + * + * @returns {string} - The new filepath for the image including full vault path and extension. + * + * Example usage: + * ``` + * onImageFilePathHook: (data) => { + * const { currentImageName, drawingFilePath } = data; + * const ext = currentImageName.split('.').pop(); + * // Generate a new filepath based on the drawing file name and other criteria + * return `${drawingFileName} - ${currentImageName || 'image'}.${ext}`; + * } + * ``` + * onImageFilePathHook: (data: { + * currentImageName: string; // Excalidraw generated name of the image, or the name received from the file system. + * drawingFilePath: string; // The full filepath of the Excalidraw file where the image is being used. + * }) => string = null; +*/ +//ea.onImageFileNameHook = (data) => {}; + /** * If set, this callback is triggered whenever the active canvas color changes * onCanvasColorChangeHook: ( diff --git a/src/constants/starutpscript.ts b/src/constants/starutpscript.ts index 260642d..ce02f03 100644 --- a/src/constants/starutpscript.ts +++ b/src/constants/starutpscript.ts @@ -3,6 +3,8 @@ f = app.vault.getAbstractFileByPath("startuphooks.md"); s = await app.vault.read(f); ea = ExcalidrawAutomate; url = await ea.convertStringToDataURL(s); +window.navigator.clipboard.writeText(`export const startupScript = () => atob("${url.split("data:text/html;base64,")[1]}");`); +console.log("String copied to clipboard"); */ -export const startupScript = () => atob("LyoKI2V4Y2x1ZGUKYGBganMqLwovKioKICogSWYgc2V0LCB0aGlzIGNhbGxiYWNrIGlzIHRyaWdnZXJlZCB3aGVuIHRoZSB1c2VyIGNsb3NlcyBhbiBFeGNhbGlkcmF3IHZpZXcuCiAqICAgb25WaWV3VW5sb2FkSG9vazogKHZpZXc6IEV4Y2FsaWRyYXdWaWV3KSA9PiB2b2lkID0gbnVsbDsKICovCi8vZWEub25WaWV3VW5sb2FkSG9vayA9ICh2aWV3KSA9PiB7fTsKCi8qKgogKiBJZiBzZXQsIHRoaXMgY2FsbGJhY2sgaXMgdHJpZ2dlcmVkLCB3aGVuIHRoZSB1c2VyIGNoYW5nZXMgdGhlIHZpZXcgbW9kZS4KICogWW91IGNhbiB1c2UgdGhpcyBjYWxsYmFjayBpbiBjYXNlIHlvdSB3YW50IHRvIGRvIHNvbWV0aGluZyBhZGRpdGlvbmFsIHdoZW4gdGhlIHVzZXIgc3dpdGNoZXMgdG8gdmlldyBtb2RlIGFuZCBiYWNrLgogKiAgIG9uVmlld01vZGVDaGFuZ2VIb29rOiAoaXNWaWV3TW9kZUVuYWJsZWQ6Ym9vbGVhbiwgdmlldzogRXhjYWxpZHJhd1ZpZXcsIGVhOiBFeGNhbGlkcmF3QXV0b21hdGUpID0+IHZvaWQgPSBudWxsOwogKi8KLy9lYS5vblZpZXdNb2RlQ2hhbmdlSG9vayA9IChpc1ZpZXdNb2RlRW5hYmxlZCwgdmlldywgZWEpID0+IHt9OwoKLyoqCiAqIElmIHNldCwgdGhpcyBjYWxsYmFjayBpcyB0cmlnZ2VyZWQsIHdoZW4gdGhlIHVzZXIgaG92ZXJzIGEgbGluayBpbiB0aGUgc2NlbmUuCiAqIFlvdSBjYW4gdXNlIHRoaXMgY2FsbGJhY2sgaW4gY2FzZSB5b3Ugd2FudCB0byBkbyBzb21ldGhpbmcgYWRkaXRpb25hbCB3aGVuIHRoZSBvbkxpbmtIb3ZlciBldmVudCBvY2N1cnMuCiAqIFRoaXMgY2FsbGJhY2sgbXVzdCByZXR1cm4gYSBib29sZWFuIHZhbHVlLgogKiBJbiBjYXNlIHlvdSB3YW50IHRvIHByZXZlbnQgdGhlIGV4Y2FsaWRyYXcgb25MaW5rSG92ZXIgYWN0aW9uIHlvdSBtdXN0IHJldHVybiBmYWxzZSwgaXQgd2lsbCBzdG9wIHRoZSBuYXRpdmUgZXhjYWxpZHJhdyBvbkxpbmtIb3ZlciBtYW5hZ2VtZW50IGZsb3cuCiAqICAgb25MaW5rSG92ZXJIb29rOiAoCiAqICAgICBlbGVtZW50OiBOb25EZWxldGVkRXhjYWxpZHJhd0VsZW1lbnQsCiAqICAgICBsaW5rVGV4dDogc3RyaW5nLAogKiAgICAgdmlldzogRXhjYWxpZHJhd1ZpZXcsCiAqICAgICBlYTogRXhjYWxpZHJhd0F1dG9tYXRlCiAqICAgKSA9PiBib29sZWFuID0gbnVsbDsKICovCi8vZWEub25MaW5rSG92ZXJIb29rID0gKGVsZW1lbnQsIGxpbmtUZXh0LCB2aWV3LCBlYSkgPT4ge307CiAgIAovKioKICogSWYgc2V0LCB0aGlzIGNhbGxiYWNrIGlzIHRyaWdnZXJlZCwgd2hlbiB0aGUgdXNlciBjbGlja3MgYSBsaW5rIGluIHRoZSBzY2VuZS4KICogWW91IGNhbiB1c2UgdGhpcyBjYWxsYmFjayBpbiBjYXNlIHlvdSB3YW50IHRvIGRvIHNvbWV0aGluZyBhZGRpdGlvbmFsIHdoZW4gdGhlIG9uTGlua0NsaWNrIGV2ZW50IG9jY3Vycy4KICogVGhpcyBjYWxsYmFjayBtdXN0IHJldHVybiBhIGJvb2xlYW4gdmFsdWUuCiAqIEluIGNhc2UgeW91IHdhbnQgdG8gcHJldmVudCB0aGUgZXhjYWxpZHJhdyBvbkxpbmtDbGljayBhY3Rpb24geW91IG11c3QgcmV0dXJuIGZhbHNlLCBpdCB3aWxsIHN0b3AgdGhlIG5hdGl2ZSBleGNhbGlkcmF3IG9uTGlua0NsaWNrIG1hbmFnZW1lbnQgZmxvdy4KICogICBvbkxpbmtDbGlja0hvb2s6KAogKiAgICAgZWxlbWVudDogRXhjYWxpZHJhd0VsZW1lbnQsCiAqICAgICBsaW5rVGV4dDogc3RyaW5nLAogKiAgICAgZXZlbnQ6IE1vdXNlRXZlbnQsCiAqICAgICB2aWV3OiBFeGNhbGlkcmF3VmlldywKICogICAgIGVhOiBFeGNhbGlkcmF3QXV0b21hdGUKICogICApID0+IGJvb2xlYW4gPSBudWxsOwogKi8KLy9lYS5vbkxpbmtDbGlja0hvb2sgPSAoZWxlbWVudCxsaW5rVGV4dCxldmVudCwgdmlldywgZWEpID0+IHt9OwogICAKLyoqCiAqIElmIHNldCwgdGhpcyBjYWxsYmFjayBpcyB0cmlnZ2VyZWQsIHdoZW4gRXhjYWxpZHJhdyByZWNlaXZlcyBhbiBvbkRyb3AgZXZlbnQuIAogKiBZb3UgY2FuIHVzZSB0aGlzIGNhbGxiYWNrIGluIGNhc2UgeW91IHdhbnQgdG8gZG8gc29tZXRoaW5nIGFkZGl0aW9uYWwgd2hlbiB0aGUgb25Ecm9wIGV2ZW50IG9jY3Vycy4KICogVGhpcyBjYWxsYmFjayBtdXN0IHJldHVybiBhIGJvb2xlYW4gdmFsdWUuCiAqIEluIGNhc2UgeW91IHdhbnQgdG8gcHJldmVudCB0aGUgZXhjYWxpZHJhdyBvbkRyb3AgYWN0aW9uIHlvdSBtdXN0IHJldHVybiBmYWxzZSwgaXQgd2lsbCBzdG9wIHRoZSBuYXRpdmUgZXhjYWxpZHJhdyBvbkRyb3AgbWFuYWdlbWVudCBmbG93LgogKiAgIG9uRHJvcEhvb2s6IChkYXRhOiB7CiAqICAgICBlYTogRXhjYWxpZHJhd0F1dG9tYXRlOwogKiAgICAgZXZlbnQ6IFJlYWN0LkRyYWdFdmVudDxIVE1MRGl2RWxlbWVudD47CiAqICAgICBkcmFnZ2FibGU6IGFueTsgLy9PYnNpZGlhbiBkcmFnZ2FibGUgb2JqZWN0CiAqICAgICB0eXBlOiAiZmlsZSIgfCAidGV4dCIgfCAidW5rbm93biI7CiAqICAgICBwYXlsb2FkOiB7CiAqICAgICAgIGZpbGVzOiBURmlsZVtdOyAvL1RGaWxlW10gYXJyYXkgb2YgZHJvcHBlZCBmaWxlcwogKiAgICAgICB0ZXh0OiBzdHJpbmc7IC8vc3RyaW5nCiAqICAgICB9OwogKiAgICAgZXhjYWxpZHJhd0ZpbGU6IFRGaWxlOyAvL3RoZSBmaWxlIHJlY2VpdmluZyB0aGUgZHJvcCBldmVudAogKiAgICAgdmlldzogRXhjYWxpZHJhd1ZpZXc7IC8vdGhlIGV4Y2FsaWRyYXcgdmlldyByZWNlaXZpbmcgdGhlIGRyb3AKICogICAgIHBvaW50ZXJQb3NpdGlvbjogeyB4OiBudW1iZXI7IHk6IG51bWJlciB9OyAvL3RoZSBwb2ludGVyIHBvc2l0aW9uIG9uIGNhbnZhcyBhdCB0aGUgdGltZSBvZiBkcm9wCiAqICAgfSkgPT4gYm9vbGVhbiA9IG51bGw7CiAqLwovL2VhLm9uRHJvcEhvb2sgPSAoZGF0YSkgPT4ge307CiAKLyoqCiAqIElmIHNldCwgdGhpcyBjYWxsYmFjayBpcyB0cmlnZ2VyZWQsIHdoZW4gRXhjYWxpZHJhdyByZWNlaXZlcyBhbiBvblBhc3RlIGV2ZW50LgogKiBZb3UgY2FuIHVzZSB0aGlzIGNhbGxiYWNrIGluIGNhc2UgeW91IHdhbnQgdG8gZG8gc29tZXRoaW5nIGFkZGl0aW9uYWwgd2hlbiB0aGUKICogb25QYXN0ZSBldmVudCBvY2N1cnMuCiAqIFRoaXMgY2FsbGJhY2sgbXVzdCByZXR1cm4gYSBib29sZWFuIHZhbHVlLgogKiBJbiBjYXNlIHlvdSB3YW50IHRvIHByZXZlbnQgdGhlIGV4Y2FsaWRyYXcgb25QYXN0ZSBhY3Rpb24geW91IG11c3QgcmV0dXJuIGZhbHNlLAogKiBpdCB3aWxsIHN0b3AgdGhlIG5hdGl2ZSBleGNhbGlkcmF3IG9uUGFzdGUgbWFuYWdlbWVudCBmbG93LgogKiAgIG9uUGFzdGVIb29rOiAoZGF0YTogewogKiAgICAgZWE6IEV4Y2FsaWRyYXdBdXRvbWF0ZTsKICogICAgIHBheWxvYWQ6IENsaXBib2FyZERhdGE7CiAqICAgICBldmVudDogQ2xpcGJvYXJkRXZlbnQ7CiAqICAgICBleGNhbGlkcmF3RmlsZTogVEZpbGU7IC8vdGhlIGZpbGUgcmVjZWl2aW5nIHRoZSBwYXN0ZSBldmVudAogKiAgICAgdmlldzogRXhjYWxpZHJhd1ZpZXc7IC8vdGhlIGV4Y2FsaWRyYXcgdmlldyByZWNlaXZpbmcgdGhlIHBhc3RlCiAqICAgICBwb2ludGVyUG9zaXRpb246IHsgeDogbnVtYmVyOyB5OiBudW1iZXIgfTsgLy90aGUgcG9pbnRlciBwb3NpdGlvbiBvbiBjYW52YXMKICogICB9KSA9PiBib29sZWFuID0gbnVsbDsKICovCi8vZWEub25QYXN0ZUhvb2sgPSAoZGF0YSkgPT4ge307CgovKioKICogaWYgc2V0LCB0aGlzIGNhbGxiYWNrIGlzIHRyaWdnZXJlZCwgd2hlbiBhbiBFeGNhbGlkcmF3IGZpbGUgaXMgb3BlbmVkCiAqIFlvdSBjYW4gdXNlIHRoaXMgY2FsbGJhY2sgaW4gY2FzZSB5b3Ugd2FudCB0byBkbyBzb21ldGhpbmcgYWRkaXRpb25hbCB3aGVuIHRoZSBmaWxlIGlzIG9wZW5lZC4KICogVGhpcyB3aWxsIHJ1biBiZWZvcmUgdGhlIGZpbGUgbGV2ZWwgc2NyaXB0IGRlZmluZWQgaW4gdGhlIGBleGNhbGlkcmF3LW9ubG9hZC1zY3JpcHRgIGZyb250bWF0dGVyLgogKiAgIG9uRmlsZU9wZW5Ib29rOiAoZGF0YTogewogKiAgICAgZWE6IEV4Y2FsaWRyYXdBdXRvbWF0ZTsKICogICAgIGV4Y2FsaWRyYXdGaWxlOiBURmlsZTsgLy90aGUgZmlsZSBiZWluZyBsb2FkZWQKICogICAgIHZpZXc6IEV4Y2FsaWRyYXdWaWV3OwogKiAgIH0pID0+IFByb21pc2U8dm9pZD47CiAqLwovL2VhLm9uRmlsZU9wZW5Ib29rID0gKGRhdGEpID0+IHt9OwoKLyoqCiAqIGlmIHNldCwgdGhpcyBjYWxsYmFjayBpcyB0cmlnZ2VyZWQsIHdoZW4gYW4gRXhjYWxpZHJhdyBmaWxlIGlzIGNyZWF0ZWQKICogc2VlIGFsc286IGh0dHBzOi8vZ2l0aHViLmNvbS96c3ZpY3ppYW4vb2JzaWRpYW4tZXhjYWxpZHJhdy1wbHVnaW4vaXNzdWVzLzExMjQKICogICBvbkZpbGVDcmVhdGVIb29rOiAoZGF0YTogewogKiAgICAgZWE6IEV4Y2FsaWRyYXdBdXRvbWF0ZTsKICogICAgIGV4Y2FsaWRyYXdGaWxlOiBURmlsZTsgLy90aGUgZmlsZSBiZWluZyBjcmVhdGVkCiAqICAgICB2aWV3OiBFeGNhbGlkcmF3VmlldzsKICogICB9KSA9PiBQcm9taXNlPHZvaWQ+OwogKi8KLy9lYS5vbkZpbGVDcmVhdGVIb29rID0gKGRhdGEpID0+IHt9OyAKCi8qKgogKiBJZiBzZXQsIHRoaXMgY2FsbGJhY2sgaXMgdHJpZ2dlcmVkIHdoZW5ldmVyIHRoZSBhY3RpdmUgY2FudmFzIGNvbG9yIGNoYW5nZXMKICogICBvbkNhbnZhc0NvbG9yQ2hhbmdlSG9vazogKAogKiAgICAgZWE6IEV4Y2FsaWRyYXdBdXRvbWF0ZSwKICogICAgIHZpZXc6IEV4Y2FsaWRyYXdWaWV3LCAvL3RoZSBleGNhbGlkcmF3IHZpZXcgCiAqICAgICBjb2xvcjogc3RyaW5nLAogKiAgICkgPT4gdm9pZCA9IG51bGw7CiAqLwovL2VhLm9uQ2FudmFzQ29sb3JDaGFuZ2VIb29rID0gKGVhLCB2aWV3LCBjb2xvcikgPT4ge307CgovKioKKiBJZiBzZXQsIHRoaXMgY2FsbGJhY2sgaXMgdHJpZ2dlcmVkIHdoZW5ldmVyIGEgZHJhd2luZyBpcyBleHBvcnRlZCB0byBTVkcuCiogVGhlIHN0cmluZyByZXR1cm5lZCB3aWxsIHJlcGxhY2UgdGhlIGxpbmsgaW4gdGhlIGV4cG9ydGVkIFNWRy4KKiBUaGUgaG9vayBpcyBvbmx5IGV4ZWN1dGVkIGlmIHRoZSBsaW5rIGlzIHRvIGEgZmlsZSBpbnRlcm5hbCB0byBPYnNpZGlhbgoqIHNlZTogaHR0cHM6Ly9naXRodWIuY29tL3pzdmljemlhbi9vYnNpZGlhbi1leGNhbGlkcmF3LXBsdWdpbi9pc3N1ZXMvMTYwNQoqICBvblVwZGF0ZUVsZW1lbnRMaW5rRm9yRXhwb3J0SG9vazogKGRhdGE6IHsKKiAgICBvcmlnaW5hbExpbms6IHN0cmluZywKKiAgICBvYnNpZGlhbkxpbms6IHN0cmluZywKKiAgICBsaW5rZWRGaWxlOiBURmlsZSB8IG51bGwsCiogICAgaG9zdEZpbGU6IFRGaWxlLAoqICB9KSA9PiBzdHJpbmcgPSBudWxsOwoqLwovL2VhLm9uVXBkYXRlRWxlbWVudExpbmtGb3JFeHBvcnRIb29rID0gKGRhdGEpID0+IHsKLy8gIGNvbnN0IGRlY29kZWRPYnNpZGlhblVSSSA9IGRlY29kZVVSSUNvbXBvbmVudChkYXRhLm9ic2lkaWFuTGluayk7Ci8vfTs="); +export const startupScript = () => atob("LyoKI2V4Y2x1ZGUKYGBganMqLwovKioKICogSWYgc2V0LCB0aGlzIGNhbGxiYWNrIGlzIHRyaWdnZXJlZCB3aGVuIHRoZSB1c2VyIGNsb3NlcyBhbiBFeGNhbGlkcmF3IHZpZXcuCiAqICAgb25WaWV3VW5sb2FkSG9vazogKHZpZXc6IEV4Y2FsaWRyYXdWaWV3KSA9PiB2b2lkID0gbnVsbDsKICovCi8vZWEub25WaWV3VW5sb2FkSG9vayA9ICh2aWV3KSA9PiB7fTsKCi8qKgogKiBJZiBzZXQsIHRoaXMgY2FsbGJhY2sgaXMgdHJpZ2dlcmVkLCB3aGVuIHRoZSB1c2VyIGNoYW5nZXMgdGhlIHZpZXcgbW9kZS4KICogWW91IGNhbiB1c2UgdGhpcyBjYWxsYmFjayBpbiBjYXNlIHlvdSB3YW50IHRvIGRvIHNvbWV0aGluZyBhZGRpdGlvbmFsIHdoZW4gdGhlIHVzZXIgc3dpdGNoZXMgdG8gdmlldyBtb2RlIGFuZCBiYWNrLgogKiAgIG9uVmlld01vZGVDaGFuZ2VIb29rOiAoaXNWaWV3TW9kZUVuYWJsZWQ6Ym9vbGVhbiwgdmlldzogRXhjYWxpZHJhd1ZpZXcsIGVhOiBFeGNhbGlkcmF3QXV0b21hdGUpID0+IHZvaWQgPSBudWxsOwogKi8KLy9lYS5vblZpZXdNb2RlQ2hhbmdlSG9vayA9IChpc1ZpZXdNb2RlRW5hYmxlZCwgdmlldywgZWEpID0+IHt9OwoKLyoqCiAqIElmIHNldCwgdGhpcyBjYWxsYmFjayBpcyB0cmlnZ2VyZWQsIHdoZW4gdGhlIHVzZXIgaG92ZXJzIGEgbGluayBpbiB0aGUgc2NlbmUuCiAqIFlvdSBjYW4gdXNlIHRoaXMgY2FsbGJhY2sgaW4gY2FzZSB5b3Ugd2FudCB0byBkbyBzb21ldGhpbmcgYWRkaXRpb25hbCB3aGVuIHRoZSBvbkxpbmtIb3ZlciBldmVudCBvY2N1cnMuCiAqIFRoaXMgY2FsbGJhY2sgbXVzdCByZXR1cm4gYSBib29sZWFuIHZhbHVlLgogKiBJbiBjYXNlIHlvdSB3YW50IHRvIHByZXZlbnQgdGhlIGV4Y2FsaWRyYXcgb25MaW5rSG92ZXIgYWN0aW9uIHlvdSBtdXN0IHJldHVybiBmYWxzZSwgaXQgd2lsbCBzdG9wIHRoZSBuYXRpdmUgZXhjYWxpZHJhdyBvbkxpbmtIb3ZlciBtYW5hZ2VtZW50IGZsb3cuCiAqICAgb25MaW5rSG92ZXJIb29rOiAoCiAqICAgICBlbGVtZW50OiBOb25EZWxldGVkRXhjYWxpZHJhd0VsZW1lbnQsCiAqICAgICBsaW5rVGV4dDogc3RyaW5nLAogKiAgICAgdmlldzogRXhjYWxpZHJhd1ZpZXcsCiAqICAgICBlYTogRXhjYWxpZHJhd0F1dG9tYXRlCiAqICAgKSA9PiBib29sZWFuID0gbnVsbDsKICovCi8vZWEub25MaW5rSG92ZXJIb29rID0gKGVsZW1lbnQsIGxpbmtUZXh0LCB2aWV3LCBlYSkgPT4ge307CiAgIAovKioKICogSWYgc2V0LCB0aGlzIGNhbGxiYWNrIGlzIHRyaWdnZXJlZCwgd2hlbiB0aGUgdXNlciBjbGlja3MgYSBsaW5rIGluIHRoZSBzY2VuZS4KICogWW91IGNhbiB1c2UgdGhpcyBjYWxsYmFjayBpbiBjYXNlIHlvdSB3YW50IHRvIGRvIHNvbWV0aGluZyBhZGRpdGlvbmFsIHdoZW4gdGhlIG9uTGlua0NsaWNrIGV2ZW50IG9jY3Vycy4KICogVGhpcyBjYWxsYmFjayBtdXN0IHJldHVybiBhIGJvb2xlYW4gdmFsdWUuCiAqIEluIGNhc2UgeW91IHdhbnQgdG8gcHJldmVudCB0aGUgZXhjYWxpZHJhdyBvbkxpbmtDbGljayBhY3Rpb24geW91IG11c3QgcmV0dXJuIGZhbHNlLCBpdCB3aWxsIHN0b3AgdGhlIG5hdGl2ZSBleGNhbGlkcmF3IG9uTGlua0NsaWNrIG1hbmFnZW1lbnQgZmxvdy4KICogICBvbkxpbmtDbGlja0hvb2s6KAogKiAgICAgZWxlbWVudDogRXhjYWxpZHJhd0VsZW1lbnQsCiAqICAgICBsaW5rVGV4dDogc3RyaW5nLAogKiAgICAgZXZlbnQ6IE1vdXNlRXZlbnQsCiAqICAgICB2aWV3OiBFeGNhbGlkcmF3VmlldywKICogICAgIGVhOiBFeGNhbGlkcmF3QXV0b21hdGUKICogICApID0+IGJvb2xlYW4gPSBudWxsOwogKi8KLy9lYS5vbkxpbmtDbGlja0hvb2sgPSAoZWxlbWVudCxsaW5rVGV4dCxldmVudCwgdmlldywgZWEpID0+IHt9OwogICAKLyoqCiAqIElmIHNldCwgdGhpcyBjYWxsYmFjayBpcyB0cmlnZ2VyZWQsIHdoZW4gRXhjYWxpZHJhdyByZWNlaXZlcyBhbiBvbkRyb3AgZXZlbnQuIAogKiBZb3UgY2FuIHVzZSB0aGlzIGNhbGxiYWNrIGluIGNhc2UgeW91IHdhbnQgdG8gZG8gc29tZXRoaW5nIGFkZGl0aW9uYWwgd2hlbiB0aGUgb25Ecm9wIGV2ZW50IG9jY3Vycy4KICogVGhpcyBjYWxsYmFjayBtdXN0IHJldHVybiBhIGJvb2xlYW4gdmFsdWUuCiAqIEluIGNhc2UgeW91IHdhbnQgdG8gcHJldmVudCB0aGUgZXhjYWxpZHJhdyBvbkRyb3AgYWN0aW9uIHlvdSBtdXN0IHJldHVybiBmYWxzZSwgaXQgd2lsbCBzdG9wIHRoZSBuYXRpdmUgZXhjYWxpZHJhdyBvbkRyb3AgbWFuYWdlbWVudCBmbG93LgogKiAgIG9uRHJvcEhvb2s6IChkYXRhOiB7CiAqICAgICBlYTogRXhjYWxpZHJhd0F1dG9tYXRlOwogKiAgICAgZXZlbnQ6IFJlYWN0LkRyYWdFdmVudDxIVE1MRGl2RWxlbWVudD47CiAqICAgICBkcmFnZ2FibGU6IGFueTsgLy9PYnNpZGlhbiBkcmFnZ2FibGUgb2JqZWN0CiAqICAgICB0eXBlOiAiZmlsZSIgfCAidGV4dCIgfCAidW5rbm93biI7CiAqICAgICBwYXlsb2FkOiB7CiAqICAgICAgIGZpbGVzOiBURmlsZVtdOyAvL1RGaWxlW10gYXJyYXkgb2YgZHJvcHBlZCBmaWxlcwogKiAgICAgICB0ZXh0OiBzdHJpbmc7IC8vc3RyaW5nCiAqICAgICB9OwogKiAgICAgZXhjYWxpZHJhd0ZpbGU6IFRGaWxlOyAvL3RoZSBmaWxlIHJlY2VpdmluZyB0aGUgZHJvcCBldmVudAogKiAgICAgdmlldzogRXhjYWxpZHJhd1ZpZXc7IC8vdGhlIGV4Y2FsaWRyYXcgdmlldyByZWNlaXZpbmcgdGhlIGRyb3AKICogICAgIHBvaW50ZXJQb3NpdGlvbjogeyB4OiBudW1iZXI7IHk6IG51bWJlciB9OyAvL3RoZSBwb2ludGVyIHBvc2l0aW9uIG9uIGNhbnZhcyBhdCB0aGUgdGltZSBvZiBkcm9wCiAqICAgfSkgPT4gYm9vbGVhbiA9IG51bGw7CiAqLwovL2VhLm9uRHJvcEhvb2sgPSAoZGF0YSkgPT4ge307CiAKLyoqCiAqIElmIHNldCwgdGhpcyBjYWxsYmFjayBpcyB0cmlnZ2VyZWQsIHdoZW4gRXhjYWxpZHJhdyByZWNlaXZlcyBhbiBvblBhc3RlIGV2ZW50LgogKiBZb3UgY2FuIHVzZSB0aGlzIGNhbGxiYWNrIGluIGNhc2UgeW91IHdhbnQgdG8gZG8gc29tZXRoaW5nIGFkZGl0aW9uYWwgd2hlbiB0aGUKICogb25QYXN0ZSBldmVudCBvY2N1cnMuCiAqIFRoaXMgY2FsbGJhY2sgbXVzdCByZXR1cm4gYSBib29sZWFuIHZhbHVlLgogKiBJbiBjYXNlIHlvdSB3YW50IHRvIHByZXZlbnQgdGhlIGV4Y2FsaWRyYXcgb25QYXN0ZSBhY3Rpb24geW91IG11c3QgcmV0dXJuIGZhbHNlLAogKiBpdCB3aWxsIHN0b3AgdGhlIG5hdGl2ZSBleGNhbGlkcmF3IG9uUGFzdGUgbWFuYWdlbWVudCBmbG93LgogKiAgIG9uUGFzdGVIb29rOiAoZGF0YTogewogKiAgICAgZWE6IEV4Y2FsaWRyYXdBdXRvbWF0ZTsKICogICAgIHBheWxvYWQ6IENsaXBib2FyZERhdGE7CiAqICAgICBldmVudDogQ2xpcGJvYXJkRXZlbnQ7CiAqICAgICBleGNhbGlkcmF3RmlsZTogVEZpbGU7IC8vdGhlIGZpbGUgcmVjZWl2aW5nIHRoZSBwYXN0ZSBldmVudAogKiAgICAgdmlldzogRXhjYWxpZHJhd1ZpZXc7IC8vdGhlIGV4Y2FsaWRyYXcgdmlldyByZWNlaXZpbmcgdGhlIHBhc3RlCiAqICAgICBwb2ludGVyUG9zaXRpb246IHsgeDogbnVtYmVyOyB5OiBudW1iZXIgfTsgLy90aGUgcG9pbnRlciBwb3NpdGlvbiBvbiBjYW52YXMKICogICB9KSA9PiBib29sZWFuID0gbnVsbDsKICovCi8vZWEub25QYXN0ZUhvb2sgPSAoZGF0YSkgPT4ge307CgovKioKICogaWYgc2V0LCB0aGlzIGNhbGxiYWNrIGlzIHRyaWdnZXJlZCwgd2hlbiBhbiBFeGNhbGlkcmF3IGZpbGUgaXMgb3BlbmVkCiAqIFlvdSBjYW4gdXNlIHRoaXMgY2FsbGJhY2sgaW4gY2FzZSB5b3Ugd2FudCB0byBkbyBzb21ldGhpbmcgYWRkaXRpb25hbCB3aGVuIHRoZSBmaWxlIGlzIG9wZW5lZC4KICogVGhpcyB3aWxsIHJ1biBiZWZvcmUgdGhlIGZpbGUgbGV2ZWwgc2NyaXB0IGRlZmluZWQgaW4gdGhlIGBleGNhbGlkcmF3LW9ubG9hZC1zY3JpcHRgIGZyb250bWF0dGVyLgogKiAgIG9uRmlsZU9wZW5Ib29rOiAoZGF0YTogewogKiAgICAgZWE6IEV4Y2FsaWRyYXdBdXRvbWF0ZTsKICogICAgIGV4Y2FsaWRyYXdGaWxlOiBURmlsZTsgLy90aGUgZmlsZSBiZWluZyBsb2FkZWQKICogICAgIHZpZXc6IEV4Y2FsaWRyYXdWaWV3OwogKiAgIH0pID0+IFByb21pc2U8dm9pZD47CiAqLwovL2VhLm9uRmlsZU9wZW5Ib29rID0gKGRhdGEpID0+IHt9OwoKLyoqCiAqIGlmIHNldCwgdGhpcyBjYWxsYmFjayBpcyB0cmlnZ2VyZWQsIHdoZW4gYW4gRXhjYWxpZHJhdyBmaWxlIGlzIGNyZWF0ZWQKICogc2VlIGFsc286IGh0dHBzOi8vZ2l0aHViLmNvbS96c3ZpY3ppYW4vb2JzaWRpYW4tZXhjYWxpZHJhdy1wbHVnaW4vaXNzdWVzLzExMjQKICogICBvbkZpbGVDcmVhdGVIb29rOiAoZGF0YTogewogKiAgICAgZWE6IEV4Y2FsaWRyYXdBdXRvbWF0ZTsKICogICAgIGV4Y2FsaWRyYXdGaWxlOiBURmlsZTsgLy90aGUgZmlsZSBiZWluZyBjcmVhdGVkCiAqICAgICB2aWV3OiBFeGNhbGlkcmF3VmlldzsKICogICB9KSA9PiBQcm9taXNlPHZvaWQ+OwogKi8KLy9lYS5vbkZpbGVDcmVhdGVIb29rID0gKGRhdGEpID0+IHt9OyAKCi8qKgogKiBJZiBzZXQsIHRoaXMgY2FsbGJhY2sgaXMgdHJpZ2dlcmVkIHdoZW4gYSBpbWFnZSBpcyBiZWluZyBzYXZlZCBpbiBFeGNhbGlkcmF3LgogKiBZb3UgY2FuIHVzZSB0aGlzIGNhbGxiYWNrIHRvIGN1c3RvbWl6ZSB0aGUgbmFtaW5nIGFuZCBwYXRoIG9mIHBhc3RlZCBpbWFnZXMgdG8gYXZvaWQKICogZGVmYXVsdCBuYW1lcyBsaWtlICJQYXN0ZWQgaW1hZ2UgMTIzMTQ3MTcwLnBuZyIgYmVpbmcgc2F2ZWQgaW4gdGhlIGF0dGFjaG1lbnRzIGZvbGRlciwKICogYW5kIGluc3RlYWQgdXNlIG1vcmUgbWVhbmluZ2Z1bCBuYW1lcyBiYXNlZCBvbiB0aGUgRXhjYWxpZHJhdyBmaWxlIG9yIG90aGVyIGNyaXRlcmlhLAogKiBwbHVzIHNhdmUgdGhlIGltYWdlIGluIGEgZGlmZmVyZW50IGZvbGRlci4KICogCiAqIElmIHRoZSBmdW5jdGlvbiByZXR1cm5zIG51bGwgb3IgdW5kZWZpbmVkLCB0aGUgbm9ybWFsIEV4Y2FsaWRyYXcgb3BlcmF0aW9uIHdpbGwgY29udGludWUKICogd2l0aCB0aGUgZXhjYWxpZHJhdyBnZW5lcmF0ZWQgbmFtZSBhbmQgZGVmYXVsdCBwYXRoLgogKiBJZiBhIGZpbGVwYXRoIGlzIHJldHVybmVkLCB0aGF0IHdpbGwgYmUgdXNlZC4gSW5jbHVkZSB0aGUgZnVsbCBWYXVsdCBmaWxlcGF0aCBhbmQgZmlsZW5hbWUKICogd2l0aCB0aGUgZmlsZSBleHRlbnNpb24uCiAqIFRoZSBjdXJyZW50SW1hZ2VOYW1lIGlzIHRoZSBuYW1lIG9mIHRoZSBpbWFnZSBnZW5lcmF0ZWQgYnkgZXhjYWxpZHJhdyBvciBwcm92aWRlZCBkdXJpbmcgcGFzdGUuCiAqIAogKiBAcGFyYW0gZGF0YSAtIEFuIG9iamVjdCBjb250YWluaW5nIHRoZSBmb2xsb3dpbmcgcHJvcGVydGllczoKICogICBAcHJvcGVydHkge3N0cmluZ30gW2N1cnJlbnRJbWFnZU5hbWVdIC0gRGVmYXVsdCBuYW1lIGZvciB0aGUgaW1hZ2UuCiAqICAgQHByb3BlcnR5IHtzdHJpbmd9IGRyYXdpbmdGaWxlUGF0aCAtIFRoZSBmaWxlIHBhdGggb2YgdGhlIEV4Y2FsaWRyYXcgZmlsZSB3aGVyZSB0aGUgaW1hZ2UgaXMgYmVpbmcgdXNlZC4KICogCiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVGhlIG5ldyBmaWxlcGF0aCBmb3IgdGhlIGltYWdlIGluY2x1ZGluZyBmdWxsIHZhdWx0IHBhdGggYW5kIGV4dGVuc2lvbi4KICogCiAqIEV4YW1wbGUgdXNhZ2U6CiAqIGBgYAogKiBvbkltYWdlRmlsZVBhdGhIb29rOiAoZGF0YSkgPT4gewogKiAgIGNvbnN0IHsgY3VycmVudEltYWdlTmFtZSwgZHJhd2luZ0ZpbGVQYXRoIH0gPSBkYXRhOwogKiAgIGNvbnN0IGV4dCA9IGN1cnJlbnRJbWFnZU5hbWUuc3BsaXQoJy4nKS5wb3AoKTsKICogICAvLyBHZW5lcmF0ZSBhIG5ldyBmaWxlcGF0aCBiYXNlZCBvbiB0aGUgZHJhd2luZyBmaWxlIG5hbWUgYW5kIG90aGVyIGNyaXRlcmlhCiAqICAgcmV0dXJuIGAke2RyYXdpbmdGaWxlTmFtZX0gLSAke2N1cnJlbnRJbWFnZU5hbWUgfHwgJ2ltYWdlJ30uJHtleHR9YDsKICogfQogKiBgYGAKICogIG9uSW1hZ2VGaWxlUGF0aEhvb2s6IChkYXRhOiB7CiAqICAgY3VycmVudEltYWdlTmFtZTogc3RyaW5nOyAvLyBFeGNhbGlkcmF3IGdlbmVyYXRlZCBuYW1lIG9mIHRoZSBpbWFnZSwgb3IgdGhlIG5hbWUgcmVjZWl2ZWQgZnJvbSB0aGUgZmlsZSBzeXN0ZW0uCiAqICAgZHJhd2luZ0ZpbGVQYXRoOiBzdHJpbmc7IC8vIFRoZSBmdWxsIGZpbGVwYXRoIG9mIHRoZSBFeGNhbGlkcmF3IGZpbGUgd2hlcmUgdGhlIGltYWdlIGlzIGJlaW5nIHVzZWQuCiAqIH0pID0+IHN0cmluZyA9IG51bGw7ICAKKi8KLy9lYS5vbkltYWdlRmlsZU5hbWVIb29rID0gKGRhdGEpID0+IHt9OwoKLyoqCiAqIElmIHNldCwgdGhpcyBjYWxsYmFjayBpcyB0cmlnZ2VyZWQgd2hlbmV2ZXIgdGhlIGFjdGl2ZSBjYW52YXMgY29sb3IgY2hhbmdlcwogKiAgIG9uQ2FudmFzQ29sb3JDaGFuZ2VIb29rOiAoCiAqICAgICBlYTogRXhjYWxpZHJhd0F1dG9tYXRlLAogKiAgICAgdmlldzogRXhjYWxpZHJhd1ZpZXcsIC8vdGhlIGV4Y2FsaWRyYXcgdmlldyAKICogICAgIGNvbG9yOiBzdHJpbmcsCiAqICAgKSA9PiB2b2lkID0gbnVsbDsKICovCi8vZWEub25DYW52YXNDb2xvckNoYW5nZUhvb2sgPSAoZWEsIHZpZXcsIGNvbG9yKSA9PiB7fTs="); \ No newline at end of file diff --git a/src/shared/ExcalidrawAutomate.ts b/src/shared/ExcalidrawAutomate.ts index 8d1c1e1..75da8dc 100644 --- a/src/shared/ExcalidrawAutomate.ts +++ b/src/shared/ExcalidrawAutomate.ts @@ -2670,6 +2670,40 @@ export class ExcalidrawAutomate { pointerPosition: { x: number; y: number }; //the pointer position on canvas }) => boolean = null; + /** + * If set, this callback is triggered when a image is being saved in Excalidraw. + * You can use this callback to customize the naming and path of pasted images to avoid + * default names like "Pasted image 123147170.png" being saved in the attachments folder, + * and instead use more meaningful names based on the Excalidraw file or other criteria, + * plus save the image in a different folder. + * + * If the function returns null or undefined, the normal Excalidraw operation will continue + * with the excalidraw generated name and default path. + * If a filepath is returned, that will be used. Include the full Vault filepath and filename + * with the file extension. + * The currentImageName is the name of the image generated by excalidraw or provided during paste. + * + * @param data - An object containing the following properties: + * @property {string} [currentImageName] - Default name for the image. + * @property {string} drawingFilePath - The file path of the Excalidraw file where the image is being used. + * + * @returns {string} - The new filepath for the image including full vault path and extension. + * + * Example usage: + * ``` + * onImageFilePathHook: (data) => { + * const { currentImageName, drawingFilePath } = data; + * // Generate a new filepath based on the drawing file name and other criteria + * const ext = currentImageName.split('.').pop(); + * return `${drawingFileName} - ${currentImageName || 'image'}.${ext}`; + * } + * ``` + */ + onImageFilePathHook: (data: { + currentImageName: string; // Excalidraw generated name of the image, or the name received from the file system. + drawingFilePath: string; // The full filepath of the Excalidraw file where the image is being used. + }) => string = null; + /** * if set, this callback is triggered, when an Excalidraw file is opened * You can use this callback in case you want to do something additional when the file is opened. diff --git a/src/shared/ExcalidrawData.ts b/src/shared/ExcalidrawData.ts index 104900a..1691435 100644 --- a/src/shared/ExcalidrawData.ts +++ b/src/shared/ExcalidrawData.ts @@ -20,7 +20,7 @@ import { loadSceneFonts, } from "../constants/constants"; import ExcalidrawPlugin from "../core/main"; -import { TextMode } from "../view/ExcalidrawView"; +import ExcalidrawView, { TextMode } from "../view/ExcalidrawView"; import { addAppendUpdateCustomData, compress, @@ -52,7 +52,7 @@ import { getMermaidImageElements, getMermaidText, shouldRenderMermaid } from ".. import { DEBUGGING, debug } from "../utils/debugHelper"; import { Mutable } from "@zsviczian/excalidraw/types/excalidraw/utility-types"; import { updateElementIdsInScene } from "../utils/excalidrawSceneUtils"; -import { getNewUniqueFilepath } from "../utils/fileUtils"; +import { getNewUniqueFilepath, splitFolderAndFilename } from "../utils/fileUtils"; import { t } from "../lang/helpers"; import { displayFontMessage } from "../utils/excalidrawViewUtils"; import { getPDFRect } from "../utils/PDFUtils"; @@ -480,7 +480,7 @@ export class ExcalidrawData { selectedElementIds: {[key:string]:boolean} = {}; //https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/609 constructor( - private plugin: ExcalidrawPlugin, + private plugin: ExcalidrawPlugin, private view?: ExcalidrawView, ) { this.app = this.plugin.app; this.files = new Map(); @@ -1546,13 +1546,23 @@ export class ExcalidrawData { } } - const x = await getAttachmentsFolderAndFilePath(this.app, this.file.path, fname); - const filepath = getNewUniqueFilepath(this.app.vault,fname,x.folder); + let hookFilepath:string; + const ea = this.view?.getHookServer(); + if(ea?.onImageFilePathHook) { + hookFilepath = ea.onImageFilePathHook({ + currentImageName: fname, + drawingFilePath: this.view?.file?.path, + }) + } - /* - const filepath = ( - await getAttachmentsFolderAndFilePath(this.app, this.file.path, fname) - ).filepath;*/ + let filepath:string; + if(hookFilepath) { + const {folderpath, filename} = splitFolderAndFilename(hookFilepath); + filepath = getNewUniqueFilepath(this.app.vault,filename,folderpath); + } else { + const x = await getAttachmentsFolderAndFilePath(this.app, this.file.path, fname); + filepath = getNewUniqueFilepath(this.app.vault,fname,x.folder); + } const arrayBuffer = await getBinaryFileFromDataURL(dataURL); if(!arrayBuffer) return null; diff --git a/src/view/ExcalidrawView.ts b/src/view/ExcalidrawView.ts index a3ad7a5..538c474 100644 --- a/src/view/ExcalidrawView.ts +++ b/src/view/ExcalidrawView.ts @@ -368,7 +368,7 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{ constructor(leaf: WorkspaceLeaf, plugin: ExcalidrawPlugin) { super(leaf); this._plugin = plugin; - this.excalidrawData = new ExcalidrawData(plugin); + this.excalidrawData = new ExcalidrawData(plugin, this); this.canvasNodeFactory = new CanvasNodeFactory(this); this.setHookServer(); this.dropManager = new DropManager(this);