Support Templater scripts in Embeddable Markdown Documents

This commit is contained in:
zsviczian
2023-08-02 22:18:43 +02:00
parent c9c5468fe4
commit 83aa04396c
9 changed files with 87 additions and 10 deletions

View File

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

View File

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

View File

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

View File

@@ -195,6 +195,7 @@ function RenderObsidianView(
containerRef.current.appendChild(rootSplit.containerEl);
}
patchMobileView(view);
view.updateEmbeddableLeafRef(element.id, leafRef.current);
})();
}

View File

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

View File

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

View File

@@ -30,6 +30,8 @@ interface ObsidianCanvas {
export interface ObsidianCanvasNode {
startEditing: Function;
child: any;
isEditing: boolean;
file: TFile;
}
export class CanvasNodeFactory {

View File

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