This commit is contained in:
zsviczian
2023-04-02 10:20:09 +02:00
parent d47a206206
commit 5c40cdb3d3
11 changed files with 121 additions and 24 deletions

View File

@@ -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",

View File

@@ -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<void>;
/**
* If set, this callback is triggered whenever the active canvas color changes
*/

View File

@@ -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<boolean> => {
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"));
}

View File

@@ -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(

View File

@@ -17,6 +17,48 @@ I develop this plugin as a hobby, spending my free time doing this. If you find
<div class="ex-coffee-div"><a href="https://ko-fi.com/zsolt"><img src="https://cdn.ko-fi.com/cdn/kofi3.png?v=3" height=45></a></div>
`,
"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<void>;
${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

View File

@@ -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<string> {
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(

View File

@@ -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: "",
},

View File

@@ -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);
}
}

View File

@@ -103,7 +103,7 @@ export class ObsidianMenu {
<label
key={index}
className={clsx(
"ToolIcon ToolIcon_type_floating",
"ToolIcon",
"ToolIcon_size_medium",
{
"is-mobile": isMobile,
@@ -168,7 +168,7 @@ export class ObsidianMenu {
<label
key = {index}
className={clsx(
"ToolIcon ToolIcon_type_floating",
"ToolIcon",
"ToolIcon_size_medium",
{
"is-mobile": isMobile,
@@ -226,7 +226,7 @@ export class ObsidianMenu {
<>
<label
className={clsx(
"ToolIcon ToolIcon_type_floating",
"ToolIcon",
"ToolIcon_size_medium",
{
"is-mobile": isMobile,

View File

@@ -55,10 +55,10 @@ export const setDynamicStyle = (
const isGray = dynamicStyle === "gray";
const gray1 = isGray
? isDark ? cmBlack().lighterBy(15) : cmBlack().darkerBy(15)
: isDark ? cmBG().lighterBy(15) : cmBG().darkerBy(15);
: isDark ? cmBG().lighterBy(15).mix({color:cmBlack(),ratio:0.6}) : cmBG().darkerBy(15).mix({color:cmBlack(),ratio:0.6});
const gray2 = isGray
? isDark ? cmBlack().lighterBy(5) : cmBlack().darkerBy(5)
: isDark ? cmBG().lighterBy(5) : cmBG().darkerBy(5);
: isDark ? cmBG().lighterBy(5).mix({color:cmBlack(),ratio:0.6}) : cmBG().darkerBy(5).mix({color:cmBlack(),ratio:0.6});
const text = cmBG().mix({color:isDark?lighter:darker, ratio:mixRatio});
const str = (cm: ColorMaster) => cm.stringHEX({alpha:false});
@@ -91,7 +91,9 @@ export const setDynamicStyle = (
`--h2-color: ${str(text)};` +
`--h3-color: ${str(text)};` +
`--h4-color: ${str(text)};` +
`color: ${str(text)};`;
`color: ${str(text)};` +
`--select-highlight-color: ${str(gray1)};` +
`--popup-bg-color: ${str(text)};`;
view.excalidrawContainer?.setAttribute(
"style",

View File

@@ -688,6 +688,8 @@ export const updateFrontmatterInString = (data:string, keyValuePairs: [string,st
const isHyperlink = (link:string) => link && !link.includes("\n") && !link.includes("\r") && link.match(/^https?:(\d*)?\/\/[^\s]*$/);
export const isContainer = (el: ExcalidrawElement) => el.type!=="arrow" && el.boundElements?.map((e) => e.type).includes("text");
export const hyperlinkIsImage = (data: string):boolean => {
if(!isHyperlink(data)) false;
const corelink = data.split("?")[0];