From 5c40cdb3d35dacfa59b78455e56f77d2e3088619 Mon Sep 17 00:00:00 2001 From: zsviczian Date: Sun, 2 Apr 2023 10:20:09 +0200 Subject: [PATCH] 1.8.22 --- manifest.json | 2 +- src/ExcalidrawAutomate.ts | 22 +++++++++++++++++-- src/ExcalidrawView.ts | 37 ++++++++++++++++++++++++------- src/Scripts.ts | 2 +- src/dialogs/Messages.ts | 42 ++++++++++++++++++++++++++++++++++++ src/dialogs/Prompt.ts | 10 +++++---- src/dialogs/SuggesterInfo.ts | 2 +- src/main.ts | 12 ++++++++++- src/menu/ObsidianMenu.tsx | 6 +++--- src/utils/DynamicStyling.ts | 8 ++++--- src/utils/Utils.ts | 2 ++ 11 files changed, 121 insertions(+), 24 deletions(-) diff --git a/manifest.json b/manifest.json index e565fb4..fd901ee 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "obsidian-excalidraw-plugin", "name": "Excalidraw", - "version": "1.8.21", + "version": "1.8.22", "minAppVersion": "1.1.6", "description": "An Obsidian plugin to edit and view Excalidraw drawings", "author": "Zsolt Viczian", diff --git a/src/ExcalidrawAutomate.ts b/src/ExcalidrawAutomate.ts index 6b4a223..845bfb0 100644 --- a/src/ExcalidrawAutomate.ts +++ b/src/ExcalidrawAutomate.ts @@ -772,9 +772,11 @@ export class ExcalidrawAutomate implements ExcalidrawAutomateInterface { wrapAt?: number; width?: number; height?: number; - textAlign?: string; + textAlign?: "left" | "center" | "right"; box?: boolean | "box" | "blob" | "ellipse" | "diamond"; boxPadding?: number; + boxStrokeColor?: string; + textVerticalAlign?: "top" | "middle" | "bottom"; }, id?: string, ): string { @@ -792,6 +794,8 @@ export class ExcalidrawAutomate implements ExcalidrawAutomateInterface { let boxId: string = null; const boxPadding = formatting?.boxPadding ?? 30; + const strokeColor = this.style.strokeColor; + this.style.strokeColor = formatting?.boxStrokeColor ?? strokeColor; if (formatting?.box) { switch (formatting.box) { case "ellipse": @@ -827,6 +831,7 @@ export class ExcalidrawAutomate implements ExcalidrawAutomateInterface { ); } } + this.style.strokeColor = strokeColor; const isContainerBound = boxId && formatting.box !== "blob"; this.elementsDict[id] = { text, @@ -835,7 +840,7 @@ export class ExcalidrawAutomate implements ExcalidrawAutomateInterface { textAlign: formatting?.textAlign ? formatting.textAlign : this.style.textAlign ?? "left", - verticalAlign: this.style.verticalAlign, + verticalAlign: formatting?.textVerticalAlign ?? this.style.verticalAlign, baseline, ...this.boxedElement(id, "text", topX, topY, width, height), containerId: isContainerBound ? boxId : null, @@ -1637,6 +1642,19 @@ export class ExcalidrawAutomate implements ExcalidrawAutomateInterface { pointerPosition: { x: number; y: number }; //the pointer position on canvas at the time of drop }) => boolean = 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. + * This will run before the file level script defined in the `excalidraw-onload-script` frontmatter. + */ + + onFileOpenHook: (data: { + ea: ExcalidrawAutomate; + excalidrawFile: TFile; //the file being loaded + view: ExcalidrawView; + }) => Promise; + + /** * If set, this callback is triggered whenever the active canvas color changes */ diff --git a/src/ExcalidrawView.ts b/src/ExcalidrawView.ts index da69478..f3f12cf 100644 --- a/src/ExcalidrawView.ts +++ b/src/ExcalidrawView.ts @@ -85,8 +85,9 @@ import { hyperlinkIsImage, hyperlinkIsYouTubeLink, getYouTubeThumbnailLink, + isContainer, } from "./utils/Utils"; -import { getLeaf, getNewOrAdjacentLeaf, getParentOfClass } from "./utils/ObsidianUtils"; +import { getLeaf, getParentOfClass } from "./utils/ObsidianUtils"; import { splitFolderAndFilename } from "./utils/FileUtils"; import { NewFileActions, Prompt } from "./dialogs/Prompt"; import { ClipboardData } from "@zsviczian/excalidraw/types/clipboard"; @@ -102,7 +103,6 @@ import { ObsidianMenu } from "./menu/ObsidianMenu"; import { ToolsPanel } from "./menu/ToolsPanel"; import { ScriptEngine } from "./Scripts"; import { getTextElementAtPointer, getImageElementAtPointer, getElementWithLinkAtPointer } from "./utils/GetElementAtPointer"; -import { MenuLinks } from "./menu/menuLinks"; import { ICONS, saveIcon } from "./menu/ActionIcons"; //import { MainMenu } from "@zsviczian/excalidraw"; //import {WelcomeScreen} from "@zsviczian/excalidraw"; @@ -110,6 +110,7 @@ import { ExportDialog } from "./dialogs/ExportDialog"; import { getEA } from "src"; import { emulateCTRLClickForLinks, externalDragModifierType, internalDragModifierType, isALT, isCTRL, isMETA, isSHIFT, linkClickModifierType, mdPropModifier, ModifierKeys } from "./utils/ModifierkeyHelper"; import { setDynamicStyle } from "./utils/DynamicStyling"; +import { MenuLinks } from "./menu/MenuLinks"; declare const PLUGIN_VERSION:string; @@ -1557,6 +1558,19 @@ export default class ExcalidrawView extends TextFileView { } } await this.loadDrawing(true); + + if(this.plugin.ea.onFileOpenHook) { + try { + await this.plugin.ea.onFileOpenHook({ + ea: getEA(this), + excalidrawFile: this.file, + view: this, + }); + } catch(e) { + errorlog({ where: "ExcalidrawView.setViewData.onFileOpenHook", error: e }); + } + } + const script = this.excalidrawData.getOnLoadScript(); if(script) { const self = this; @@ -2444,7 +2458,7 @@ export default class ExcalidrawView extends TextFileView { images: any, newElementsOnTop: boolean = false, ): Promise => { - const api = this.excalidrawAPI; + const api = this.excalidrawAPI as ExcalidrawImperativeAPI; if (!excalidrawRef?.current || !api) { return false; } @@ -2480,7 +2494,7 @@ export default class ExcalidrawView extends TextFileView { } const newIds = newElements.map((e) => e.id); - const el: ExcalidrawElement[] = api.getSceneElements(); + const el: ExcalidrawElement[] = api.getSceneElements() as ExcalidrawElement[]; const removeList: string[] = []; //need to update elements in scene.elements to maintain sequence of layers @@ -2540,6 +2554,7 @@ export default class ExcalidrawView extends TextFileView { }); api.addFiles(files); } + api.updateContainerSize(api.getSceneElements().filter(el => newIds.includes(el.id)).filter(isContainer)); if (save) { await this.save(false); //preventReload=false will ensure that markdown links are paresed and displayed correctly } else { @@ -2698,6 +2713,7 @@ export default class ExcalidrawView extends TextFileView { if(!mouseEvent) return; if(this.excalidrawAPI?.getAppState()?.editingElement) return; //should not activate hover preview when element is being edited if(this.semaphores.wheelTimeout) return; + //if link text is not provided, try to get it from the element if (!linktext) { if(!this.currentPosition) return; linktext = ""; @@ -2714,6 +2730,8 @@ export default class ExcalidrawView extends TextFileView { } const ef = this.excalidrawData.getFile(selectedImgElement.fileId); if(ef.isHyperlink) return; //web images don't have a preview + if(IMAGE_TYPES.contains(ef.file.extension)) return; //images don't have a preview + if(this.plugin.ea.isExcalidrawFile(ef.file)) return; //excalidraw files don't have a preview const ref = ef.linkParts.ref ? `#${ef.linkParts.isBlockRef ? "^" : ""}${ef.linkParts.ref}` : ""; @@ -3723,9 +3741,7 @@ export default class ExcalidrawView extends TextFileView { .filter((el: ExcalidrawElement) => el.id === containerId && el.type!=="arrow") : api .getSceneElements() - .filter((el: ExcalidrawElement) => - el.type!=="arrow" && el.boundElements?.map((e) => e.type).includes("text"), - ); + .filter(isContainer); if (containers.length > 0) { if (this.initialContainerSizeUpdate) { //updateContainerSize will bump scene version which will trigger a false autosave @@ -3936,9 +3952,14 @@ export default class ExcalidrawView extends TextFileView { "Set link alias", "Leave empty if you do not want to set an alias", "", + [ + {caption: "Link", action:()=>{prefix="";return}}, + {caption: "Area", action:()=>{prefix="area="; return;}}, + {caption: "Group", action:()=>{prefix="group="; return;}} + ] ); navigator.clipboard.writeText( - `[[${this.file.path}#^${prefix}${elementId}${alias ? `|${alias}` : ``}]]`, + `${prefix.length>0?"!":""}[[${this.file.path}#^${prefix}${elementId}${alias ? `|${alias}` : ``}]]`, ); new Notice(t("INSERT_LINK_TO_ELEMENT_READY")); } diff --git a/src/Scripts.ts b/src/Scripts.ts index 185c290..8e5f0b5 100644 --- a/src/Scripts.ts +++ b/src/Scripts.ts @@ -272,7 +272,7 @@ export class ScriptEngine { header: string, placeholder?: string, value?: string, - buttons?: [{ caption: string; action: Function }], + buttons?: { caption: string; action: Function }[], ) { try { return await GenericInputPrompt.Prompt( diff --git a/src/dialogs/Messages.ts b/src/dialogs/Messages.ts index 0e6df5a..bdf5e67 100644 --- a/src/dialogs/Messages.ts +++ b/src/dialogs/Messages.ts @@ -17,6 +17,48 @@ I develop this plugin as a hobby, spending my free time doing this. If you find
`, +"1.8.22": ` +## Fixed +- Styling of custom pen and script buttons in the side pannel was inverted. +- Minor tweaks to dynamic styling. [see this video to understand dynamic styling](https://youtu.be/fypDth_-8q0) + +## New +- New scripts by @threethan: + - [Auto Draw for Pen](https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Auto%20Draw%20for%20Pen.md): Automatically switches between the select and draw tools, based on whether a pen is being used. Supports most pens including Apple Pencil. + - [Hardware Eraser Support](https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Hardware%20Eraser%20Support.md): Adds support for pen inversion, a.k.a. the hardware eraser on the back of your pen. Supports Windows based styluses. Does not suppoprt Apple Pencil or S-Pen. +- Added separate buttons to support copying link, area or group references to objects on the drawing. [#1063](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/1063). See [this video](https://youtu.be/yZQoJg2RCKI) for more details on how this works. +- Hover preview will no long trigger for image files (.png, .svg, .jpg, .gif, .webp, .bmp, .ico, .excalidraw) +- Minor updates to the [Slideshow](https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Slideshow.md) script. You can download the updated script from the Excalidraw script library. The slideshow will now correctly run also when initiated in a popout window. When the drawing is in a popout window, the slideshow will not be full screen, but will only occupy the popout window. If you run the slideshow from the main Obsidian workspace, it will be displayed in full-screen mode. +- Updated the Icon Library script to now include image keywords under each of the images to allow searching for keywords (CTRL/CMD+F). I've uploaded the new script to [here](https://gist.github.com/zsviczian/33ff695d5b990de1ebe8b82e541c26ad). If you need further information watch this [video](https://youtu.be/_OEljzZ33H8) + +## New in ExcalidrawAutomate +- ${String.fromCharCode(96)}addText${String.fromCharCode(96)} ${String.fromCharCode(96)}formatting${String.fromCharCode(96)} parameter now accepts ${String.fromCharCode(96)}boxStrokeColor${String.fromCharCode(96)} and ${String.fromCharCode(96)}textVerticalAlign${String.fromCharCode(96)} values. +${String.fromCharCode(96,96,96)}typescript +addText( + topX: number, + topY: number, + text: string, + formatting?: { + wrapAt?: number; + width?: number; + height?: number; + textAlign?: "left" | "center" | "right"; + box?: boolean | "box" | "blob" | "ellipse" | "diamond"; + boxPadding?: number; + boxStrokeColor?: string; + textVerticalAlign?: "top" | "middle" | "bottom"; + }, + id?: string, + ): string; +${String.fromCharCode(96,96,96)} +- new ${String.fromCharCode(96)}onFileOpenHook${String.fromCharCode(96)}. 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. This will run before the file level script defined in the ${String.fromCharCode(96)}excalidraw-onload-script${String.fromCharCode(96)} frontmatter is executed. Excalidraw will await the result of operations here. Handle with care. If you change data such as the frontmatter of the underlying file, I haven't tested how it will behave. +${String.fromCharCode(96,96,96)}typescript +onFileOpenHook: (data: { + ea: ExcalidrawAutomate; + excalidrawFile: TFile; //the file being loaded + view: ExcalidrawView; +}) => Promise; +${String.fromCharCode(96,96,96)}`, "1.8.21": ` ## Quality of Life improvements - Dynamic Styling (see plugin settings / Display). When Dynamic Styling is enabled it fixes Excalidraw issues with the Minimal Theme diff --git a/src/dialogs/Prompt.ts b/src/dialogs/Prompt.ts index af97a85..aea80e5 100644 --- a/src/dialogs/Prompt.ts +++ b/src/dialogs/Prompt.ts @@ -79,7 +79,7 @@ export class GenericInputPrompt extends Modal { private didSubmit: boolean = false; private inputComponent: TextComponent; private input: string; - private buttons: [{ caption: string; action: Function }]; + private buttons: { caption: string; action: Function }[]; private readonly placeholder: string; public static Prompt( @@ -87,7 +87,7 @@ export class GenericInputPrompt extends Modal { header: string, placeholder?: string, value?: string, - buttons?: [{ caption: string; action: Function }], + buttons?: { caption: string; action: Function }[], ): Promise { const newPromptModal = new GenericInputPrompt( app, @@ -104,7 +104,7 @@ export class GenericInputPrompt extends Modal { private header: string, placeholder?: string, value?: string, - buttons?: [{ caption: string; action: Function }], + buttons?: { caption: string; action: Function }[], ) { super(app); this.placeholder = placeholder; @@ -166,6 +166,7 @@ export class GenericInputPrompt extends Modal { let b = null; for (const button of this.buttons) { const btn = new ButtonComponent(buttonBarContainer); + btn.buttonEl.style.marginLeft="5px"; btn.setButtonText(button.caption).onClick((evt: MouseEvent) => { const res = button.action(this.input); if (res) { @@ -176,7 +177,8 @@ export class GenericInputPrompt extends Modal { b = b ?? btn; } if (b) { - b.setCta().buttonEl.style.marginRight = "0"; + b.setCta(); + b.buttonEl.style.marginRight = "0"; } } else { this.createButton( diff --git a/src/dialogs/SuggesterInfo.ts b/src/dialogs/SuggesterInfo.ts index 85ce895..5522f30 100644 --- a/src/dialogs/SuggesterInfo.ts +++ b/src/dialogs/SuggesterInfo.ts @@ -206,7 +206,7 @@ export const EXCALIDRAW_AUTOMATE_INFO: SuggesterInfo[] = [ }, { field: "addText", - code: 'addText(topX: number, topY: number, text: string, formatting?: {wrapAt?: number; width?: number; height?: number; textAlign?: string; box?: boolean | "box" | "blob" | "ellipse" | "diamond"; boxPadding?: number;}, id?: string,): string;', + code: 'addText(topX: number, topY: number, text: string, formatting?: {wrapAt?: number; width?: number; height?: number; textAlign?: "left" | "center" | "right"; textVerticalAlign: "top" | "middle" | "bottom"; box?: boolean | "box" | "blob" | "ellipse" | "diamond"; boxPadding?: number; boxStrokeColor?: string;}, id?: string,): string;', desc: "If box is !null, then text will be boxed\nThe function returns the id of the TextElement. If the text element is boxed i.e. it is a sticky note, then the id of the container object", after: "", }, diff --git a/src/main.ts b/src/main.ts index 8d00da1..5891c0b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1833,7 +1833,16 @@ export default class ExcalidrawPlugin extends Plugin { const scope = self.app.keymap.getRootScope(); const handler_ctrlEnter = scope.register(["Mod"], "Enter", () => true); scope.keys.unshift(scope.keys.pop()); // Force our handler to the front of the list - const handler_ctrlK = scope.register(["Mod"], "k", () => {console.log("keydown"); return true}); + const handler_ctrlK = scope.register(["Mod"], "k", () => {return true}); + scope.keys.unshift(scope.keys.pop()); // Force our handler to the front of the list + const handler_ctrlF = scope.register(["Mod"], "f", () => { + const view = this.app.workspace.getActiveViewOfType(ExcalidrawView); + if (view) { + search(view); + return true; + } + return false; + }); scope.keys.unshift(scope.keys.pop()); // Force our handler to the front of the list const overridSaveShortcut = ( self.forceSaveCommand && @@ -1849,6 +1858,7 @@ export default class ExcalidrawPlugin extends Plugin { self.popScope = () => { scope.unregister(handler_ctrlEnter); scope.unregister(handler_ctrlK); + scope.unregister(handler_ctrlF); Boolean(saveHandler) && scope.unregister(saveHandler); } } diff --git a/src/menu/ObsidianMenu.tsx b/src/menu/ObsidianMenu.tsx index e085d7b..abd996c 100644 --- a/src/menu/ObsidianMenu.tsx +++ b/src/menu/ObsidianMenu.tsx @@ -103,7 +103,7 @@ export class ObsidianMenu {