mirror of
https://github.com/zsviczian/obsidian-excalidraw-plugin.git
synced 2025-08-06 05:46:28 +00:00
Support Templater scripts in Embeddable Markdown Documents
This commit is contained in:
@@ -11,7 +11,7 @@ import {
|
||||
StrokeRoundness,
|
||||
RoundnessType,
|
||||
} from "@zsviczian/excalidraw/types/element/types";
|
||||
import { normalizePath, Notice, TFile, WorkspaceLeaf } from "obsidian";
|
||||
import { normalizePath, Notice, OpenViewState, TFile, WorkspaceLeaf } from "obsidian";
|
||||
import * as obsidian_module from "obsidian";
|
||||
import ExcalidrawView, { ExportSettings, TextMode } from "src/ExcalidrawView";
|
||||
import { ExcalidrawData, getMarkdownDrawingSection } from "src/ExcalidrawData";
|
||||
@@ -2010,10 +2010,11 @@ export class ExcalidrawAutomate {
|
||||
|
||||
/**
|
||||
* Open a file in a new workspaceleaf or reuse an existing adjacent leaf depending on Excalidraw Plugin Settings
|
||||
* @param file
|
||||
* @param file
|
||||
* @param openState - if not provided {active: true} will be used
|
||||
* @returns
|
||||
*/
|
||||
openFileInNewOrAdjacentLeaf(file: TFile): WorkspaceLeaf {
|
||||
openFileInNewOrAdjacentLeaf(file: TFile, openState?: OpenViewState): WorkspaceLeaf {
|
||||
if (!file || !(file instanceof TFile)) {
|
||||
return null;
|
||||
}
|
||||
@@ -2021,7 +2022,7 @@ export class ExcalidrawAutomate {
|
||||
return null;
|
||||
}
|
||||
const leaf = getNewOrAdjacentLeaf(this.plugin, this.targetView.leaf);
|
||||
leaf.openFile(file, {active: true});
|
||||
leaf.openFile(file, openState ?? {active: true});
|
||||
return leaf;
|
||||
};
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ import { InsertPDFModal } from "./dialogs/InsertPDFModal";
|
||||
import { CustomEmbeddable, renderWebView } from "./customEmbeddable";
|
||||
import { insertEmbeddableToView, insertImageToView } from "./utils/ExcalidrawViewUtils";
|
||||
import { imageCache } from "./utils/ImageCache";
|
||||
import { CanvasNodeFactory } from "./utils/CanvasNodeFactory";
|
||||
import { CanvasNodeFactory, ObsidianCanvasNode } from "./utils/CanvasNodeFactory";
|
||||
import { EmbeddableMenu } from "./menu/EmbeddableActionsMenu";
|
||||
import { useDefaultExcalidrawFrame } from "./utils/CustomEmbeddableUtils";
|
||||
import { UniversalInsertFileModal } from "./dialogs/UniversalInsertFileModal";
|
||||
@@ -255,6 +255,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
private draginfoDiv: HTMLDivElement;
|
||||
public canvasNodeFactory: CanvasNodeFactory;
|
||||
private embeddableRefs = new Map<ExcalidrawElement["id"], HTMLIFrameElement | HTMLWebViewElement>();
|
||||
private embeddableLeafRefs = new Map<ExcalidrawElement["id"], any>();
|
||||
|
||||
public semaphores: {
|
||||
popoutUnload: boolean; //the unloaded Excalidraw view was the last leaf in the popout window
|
||||
@@ -1626,6 +1627,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
clear() {
|
||||
this.canvasNodeFactory.purgeNodes();
|
||||
this.embeddableRefs.clear();
|
||||
this.embeddableLeafRefs.clear();
|
||||
|
||||
delete this.exportDialog;
|
||||
const api = this.excalidrawAPI;
|
||||
@@ -4467,6 +4469,42 @@ export default class ExcalidrawView extends TextFileView {
|
||||
public getEmbeddableElementById(id: string): HTMLIFrameElement | HTMLWebViewElement | undefined {
|
||||
return this.embeddableRefs.get(id);
|
||||
}
|
||||
|
||||
public updateEmbeddableLeafRef(id: string, ref: any) {
|
||||
if(ref) {
|
||||
this.embeddableLeafRefs.set(id, ref);
|
||||
}
|
||||
}
|
||||
|
||||
public getEmbeddableLeafElementById(id: string): {leaf: WorkspaceLeaf; node?: ObsidianCanvasNode} | null {
|
||||
const ref = this.embeddableLeafRefs.get(id);
|
||||
if(!ref) {
|
||||
return null;
|
||||
}
|
||||
return ref as {leaf: WorkspaceLeaf; node?: ObsidianCanvasNode};
|
||||
}
|
||||
|
||||
getActiveEmbeddable = ():{leaf: WorkspaceLeaf; node?: ObsidianCanvasNode}|null => {
|
||||
if(!this.excalidrawAPI) return null;
|
||||
const api = this.excalidrawAPI as ExcalidrawImperativeAPI;
|
||||
const st = api.getAppState();
|
||||
if(!st.activeEmbeddable || st.activeEmbeddable.state !== "active" ) return null;
|
||||
return this.getEmbeddableLeafElementById(st.activeEmbeddable?.element?.id);
|
||||
}
|
||||
|
||||
get editor(): any {
|
||||
const embeddable = this.getActiveEmbeddable();
|
||||
if(embeddable) {
|
||||
if(embeddable.node && embeddable.node.isEditing) {
|
||||
return embeddable.node.child.editor;
|
||||
}
|
||||
if(embeddable.leaf?.view instanceof MarkdownView) {
|
||||
return embeddable.leaf.view.editor;
|
||||
}
|
||||
}
|
||||
app.workspace.openLinkText
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function getTextMode(data: string): TextMode {
|
||||
|
||||
@@ -73,9 +73,9 @@ export const SCRIPT_INSTALL_CODEBLOCK = "excalidraw-script-install";
|
||||
export const SCRIPT_INSTALL_FOLDER = "Downloaded";
|
||||
export const fileid = customAlphabet("1234567890abcdef", 40);
|
||||
export const REG_LINKINDEX_INVALIDCHARS = /[<>:"\\|?*#]/g;
|
||||
export const REG_BLOCK_REF_CLEAN =
|
||||
/[!"#$%&()*+,.:;<=>?@^`{|}~\/\[\]\\]/g; //https://discord.com/channels/686053708261228577/989603365606531104/1000128926619816048
|
||||
// /\+|\/|~|=|%|\(|\)|{|}|,|&|\.|\$|!|\?|;|\[|]|\^|#|\*|<|>|&|@|\||\\|"|:|\s/g;
|
||||
export const REG_BLOCK_REF_CLEAN = /[!"#$%&()*+,.:;<=>?@^`{|}~\/\[\]\\]/g;
|
||||
// https://discord.com/channels/686053708261228577/989603365606531104/1000128926619816048
|
||||
// /\+|\/|~|=|%|\(|\)|{|}|,|&|\.|\$|!|\?|;|\[|]|\^|#|\*|<|>|&|@|\||\\|"|:|\s/g;
|
||||
export const IMAGE_TYPES = ["jpeg", "jpg", "png", "gif", "svg", "webp", "bmp", "ico"];
|
||||
export const EXPORT_TYPES = ["svg", "dark.svg", "light.svg", "png", "dark.png", "light.png"];
|
||||
export const MAX_IMAGE_SIZE = 500;
|
||||
|
||||
@@ -195,6 +195,7 @@ function RenderObsidianView(
|
||||
containerRef.current.appendChild(rootSplit.containerEl);
|
||||
}
|
||||
patchMobileView(view);
|
||||
view.updateEmbeddableLeafRef(element.id, leafRef.current);
|
||||
})();
|
||||
}
|
||||
|
||||
|
||||
26
src/main.ts
26
src/main.ts
@@ -17,6 +17,7 @@ import {
|
||||
MetadataCache,
|
||||
FrontMatterCache,
|
||||
Command,
|
||||
Workspace,
|
||||
} from "obsidian";
|
||||
import {
|
||||
BLANK_DRAWING,
|
||||
@@ -63,7 +64,7 @@ import {
|
||||
search,
|
||||
} from "./ExcalidrawAutomate";
|
||||
import { Prompt } from "./dialogs/Prompt";
|
||||
import { around } from "monkey-around";
|
||||
import { around, dedupe } from "monkey-around";
|
||||
import { t } from "./lang/helpers";
|
||||
import {
|
||||
checkAndCreateFolder,
|
||||
@@ -82,6 +83,7 @@ import {
|
||||
debug,
|
||||
isVersionNewerThanOther,
|
||||
getExportTheme,
|
||||
isCallerFromTemplaterPlugin,
|
||||
} from "./utils/Utils";
|
||||
import { getAttachmentsFolderAndFilePath, getNewOrAdjacentLeaf, getParentOfClass, isObsidianThemeDark } from "./utils/ObsidianUtils";
|
||||
//import { OneOffs } from "./OneOffs";
|
||||
@@ -1578,6 +1580,28 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
}
|
||||
|
||||
private registerMonkeyPatches() {
|
||||
const key = "https://github.com/zsviczian/obsidian-excalidraw-plugin/issues";
|
||||
this.register(
|
||||
around(Workspace.prototype, {
|
||||
getActiveViewOfType(old) {
|
||||
return dedupe(key, old, function(...args) {
|
||||
const result = old && old.apply(this, args);
|
||||
const maybeEAView = app?.workspace?.activeLeaf?.view;
|
||||
if(!maybeEAView || !(maybeEAView instanceof ExcalidrawView)) return result;
|
||||
const error = new Error();
|
||||
const stackTrace = error.stack;
|
||||
if(!isCallerFromTemplaterPlugin(stackTrace)) return result;
|
||||
const leafOrNode = maybeEAView.getActiveEmbeddable();
|
||||
if(leafOrNode) {
|
||||
if(leafOrNode.node && leafOrNode.node.isEditing) {
|
||||
return {file: leafOrNode.node.file, editor: leafOrNode.node.child.editor};
|
||||
}
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
})
|
||||
);
|
||||
//@ts-ignore
|
||||
if(!app.plugins?.plugins?.["obsidian-hover-editor"]) {
|
||||
this.register( //stolen from hover editor
|
||||
|
||||
@@ -53,6 +53,7 @@ export class EmbeddableMenu {
|
||||
const view = this.view;
|
||||
const api = view?.excalidrawAPI as ExcalidrawImperativeAPI;
|
||||
if(!api) return null;
|
||||
if(!view.file) return null;
|
||||
const disableFrameButtons = appState.viewModeEnabled && !view.allowFrameButtonsInViewMode;
|
||||
if(!appState.activeEmbeddable || appState.activeEmbeddable.state !== "active" || disableFrameButtons) {
|
||||
this.menuElementId = null;
|
||||
|
||||
@@ -30,6 +30,8 @@ interface ObsidianCanvas {
|
||||
export interface ObsidianCanvasNode {
|
||||
startEditing: Function;
|
||||
child: any;
|
||||
isEditing: boolean;
|
||||
file: TFile;
|
||||
}
|
||||
|
||||
export class CanvasNodeFactory {
|
||||
|
||||
@@ -725,4 +725,14 @@ export const getYouTubeThumbnailLink = async (youtubelink: string):Promise<strin
|
||||
|
||||
|
||||
return `https://i.ytimg.com/vi/${videoId}/default.jpg`;
|
||||
}
|
||||
|
||||
export const isCallerFromTemplaterPlugin = (stackTrace:string) => {
|
||||
const lines = stackTrace.split("\n");
|
||||
for (const line of lines) {
|
||||
if (line.trim().startsWith("at Templater.")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
Reference in New Issue
Block a user