mirror of
https://github.com/zsviczian/obsidian-excalidraw-plugin.git
synced 2025-08-06 05:46:28 +00:00
1845 lines
63 KiB
TypeScript
1845 lines
63 KiB
TypeScript
import {
|
|
TFile,
|
|
App,
|
|
MarkdownView,
|
|
normalizePath,
|
|
Menu,
|
|
MenuItem,
|
|
Notice,
|
|
Command,
|
|
EventRef,
|
|
FileView,
|
|
} from "obsidian";
|
|
import {
|
|
VIEW_TYPE_EXCALIDRAW,
|
|
ICON_NAME,
|
|
IMAGE_TYPES,
|
|
DEVICE,
|
|
sceneCoordsToViewportCoords,
|
|
fileid,
|
|
} from "../../constants/constants";
|
|
import ExcalidrawView, { TextMode } from "../../view/ExcalidrawView";
|
|
import {
|
|
REGEX_LINK,
|
|
} from "../../shared/ExcalidrawData";
|
|
import { ExcalidrawSettings } from "../settings";
|
|
import { openDialogAction, OpenFileDialog } from "../../shared/Dialogs/OpenDrawing";
|
|
import { InsertLinkDialog } from "../../shared/Dialogs/InsertLinkDialog";
|
|
import { InsertCommandDialog } from "../../shared/Dialogs/InsertCommandDialog";
|
|
import { InsertImageDialog } from "../../shared/Dialogs/InsertImageDialog";
|
|
import { ImportSVGDialog } from "../../shared/Dialogs/ImportSVGDialog";
|
|
import { InsertMDDialog } from "../../shared/Dialogs/InsertMDDialog";
|
|
import { ExcalidrawAutomate } from "../../shared/ExcalidrawAutomate";
|
|
import { insertLaTeXToView, search } from "src/utils/excalidrawAutomateUtils";
|
|
import { templatePromt } from "../../shared/Dialogs/Prompt";
|
|
import { t } from "../../lang/helpers";
|
|
import {
|
|
getAliasWithSize,
|
|
getAnnotationFileNameAndFolder,
|
|
getCropFileNameAndFolder,
|
|
getDrawingFilename,
|
|
getEmbedFilename,
|
|
getIMGFilename,
|
|
getLink,
|
|
getListOfTemplateFiles,
|
|
getURLImageExtension,
|
|
} from "../../utils/fileUtils";
|
|
import {
|
|
setLeftHandedMode,
|
|
sleep,
|
|
decompress,
|
|
getImageSize,
|
|
} from "../../utils/utils";
|
|
import { extractSVGPNGFileName, getActivePDFPageNumberFromPDFView, getAttachmentsFolderAndFilePath, isObsidianThemeDark, mergeMarkdownFiles, setExcalidrawView } from "../../utils/obsidianUtils";
|
|
import { ExcalidrawElement, ExcalidrawEmbeddableElement, ExcalidrawImageElement, ExcalidrawTextElement, FileId } from "@zsviczian/excalidraw/types/excalidraw/element/types";
|
|
import { ReleaseNotes } from "../../shared/Dialogs/ReleaseNotes";
|
|
import { ScriptInstallPrompt } from "../../shared/Dialogs/ScriptInstallPrompt";
|
|
import Taskbone from "../../shared/OCR/Taskbone";
|
|
import { emulateCTRLClickForLinks, linkClickModifierType, PaneTarget } from "../../utils/modifierkeyHelper";
|
|
import { InsertPDFModal } from "../../shared/Dialogs/InsertPDFModal";
|
|
import { ExportDialog } from "../../shared/Dialogs/ExportDialog";
|
|
import { UniversalInsertFileModal } from "../../shared/Dialogs/UniversalInsertFileModal";
|
|
import { PublishOutOfDateFilesDialog } from "../../shared/Dialogs/PublishOutOfDateFiles";
|
|
import { EmbeddableSettings } from "../../shared/Dialogs/EmbeddableSettings";
|
|
import { processLinkText } from "../../utils/customEmbeddableUtils";
|
|
import { getEA } from "src/core";
|
|
import { ExcalidrawImperativeAPI } from "@zsviczian/excalidraw/types/excalidraw/types";
|
|
import { Mutable } from "@zsviczian/excalidraw/types/excalidraw/utility-types";
|
|
import { carveOutImage, carveOutPDF, createImageCropperFile } from "../../utils/carveout";
|
|
import { showFrameSettings } from "../../shared/Dialogs/FrameSettings";
|
|
import { insertImageToView } from "../../utils/excalidrawViewUtils";
|
|
import ExcalidrawPlugin from "src/core/main";
|
|
import { get } from "http";
|
|
|
|
declare const PLUGIN_VERSION:string;
|
|
|
|
export class CommandManager {
|
|
private app: App;
|
|
private plugin: ExcalidrawPlugin;
|
|
private openDialog: OpenFileDialog;
|
|
public insertLinkDialog: InsertLinkDialog;
|
|
public insertCommandDialog: InsertCommandDialog;
|
|
public insertImageDialog: InsertImageDialog;
|
|
public importSVGDialog: ImportSVGDialog;
|
|
public insertMDDialog: InsertMDDialog;
|
|
public taskbone: Taskbone;
|
|
public forceSaveCommand:Command;
|
|
|
|
get settings(): ExcalidrawSettings {
|
|
return this.plugin.settings;
|
|
}
|
|
|
|
get ea(): ExcalidrawAutomate {
|
|
return this.plugin.ea;
|
|
}
|
|
|
|
private isExcalidrawFile(file: TFile): boolean {
|
|
return this.plugin.isExcalidrawFile(file);
|
|
}
|
|
|
|
constructor(plugin: ExcalidrawPlugin) {
|
|
this.app = plugin.app;
|
|
this.plugin = plugin;
|
|
}
|
|
|
|
public initialize() {
|
|
try {
|
|
this.taskbone = new Taskbone(this.plugin);
|
|
this.registerCommands();
|
|
} catch (e) {
|
|
new Notice("Error registering commands", 6000);
|
|
console.error("Error registering commands", e);
|
|
}
|
|
this.plugin.logStartupEvent("Commands registered");
|
|
}
|
|
|
|
destroy() {
|
|
this.openDialog.destroy();
|
|
this.openDialog = null;
|
|
this.insertLinkDialog.destroy();
|
|
this.insertLinkDialog = null;
|
|
this.insertCommandDialog.destroy();
|
|
this.insertCommandDialog = null;
|
|
this.importSVGDialog.destroy();
|
|
this.importSVGDialog = null;
|
|
this.insertImageDialog.destroy();
|
|
this.insertImageDialog = null;
|
|
this.insertMDDialog.destroy();
|
|
this.insertMDDialog = null;
|
|
if (this.taskbone) {
|
|
this.taskbone.destroy();
|
|
this.taskbone = null;
|
|
}
|
|
this.forceSaveCommand = null;
|
|
}
|
|
|
|
private registerEvent(event: EventRef): void {
|
|
this.plugin.registerEvent(event);
|
|
}
|
|
|
|
private addCommand(command: Command): Command {
|
|
return this.plugin.addCommand(command);
|
|
}
|
|
|
|
private registerCommands() {
|
|
this.openDialog = new OpenFileDialog(this.app, this.plugin);
|
|
this.insertLinkDialog = new InsertLinkDialog(this.plugin);
|
|
this.insertCommandDialog = new InsertCommandDialog(this.app);
|
|
this.insertImageDialog = new InsertImageDialog(this.plugin);
|
|
this.importSVGDialog = new ImportSVGDialog(this.plugin);
|
|
this.insertMDDialog = new InsertMDDialog(this.plugin);
|
|
|
|
const createNewAction = (e: MouseEvent | KeyboardEvent, file: TFile) => {
|
|
let folderpath = file.path;
|
|
if (file instanceof TFile) {
|
|
folderpath = normalizePath(
|
|
file.path.substr(0, file.path.lastIndexOf(file.name)),
|
|
);
|
|
}
|
|
this.plugin.createAndOpenDrawing(
|
|
getDrawingFilename(this.settings),
|
|
linkClickModifierType(emulateCTRLClickForLinks(e)),
|
|
folderpath,
|
|
);
|
|
}
|
|
|
|
const fileMenuHandlerCreateNew = (menu: Menu, file: TFile) => {
|
|
menu.addItem((item: MenuItem) => {
|
|
item
|
|
.setTitle(t("CREATE_NEW"))
|
|
.setIcon(ICON_NAME)
|
|
.onClick((e) => {createNewAction(e, file)});
|
|
});
|
|
};
|
|
|
|
this.registerEvent(
|
|
this.app.workspace.on("file-menu", fileMenuHandlerCreateNew),
|
|
);
|
|
|
|
const fileMenuHandlerConvertKeepExtension = (menu: Menu, file: TFile) => {
|
|
if (file instanceof TFile && file.extension == "excalidraw") {
|
|
menu.addItem((item: MenuItem) => {
|
|
item.setTitle(t("CONVERT_FILE_KEEP_EXT")).onClick(() => {
|
|
this.plugin.convertSingleExcalidrawToMD(file, false, false);
|
|
});
|
|
});
|
|
}
|
|
};
|
|
|
|
this.registerEvent(
|
|
this.app.workspace.on("file-menu", fileMenuHandlerConvertKeepExtension),
|
|
);
|
|
|
|
const fileMenuHandlerConvertReplaceExtension = (
|
|
menu: Menu,
|
|
file: TFile,
|
|
) => {
|
|
if (file instanceof TFile && file.extension == "excalidraw") {
|
|
menu.addItem((item: MenuItem) => {
|
|
item.setTitle(t("CONVERT_FILE_REPLACE_EXT")).onClick(() => {
|
|
this.plugin.convertSingleExcalidrawToMD(file, true, true);
|
|
});
|
|
});
|
|
}
|
|
};
|
|
|
|
this.registerEvent(
|
|
this.app.workspace.on(
|
|
"file-menu",
|
|
fileMenuHandlerConvertReplaceExtension,
|
|
),
|
|
);
|
|
|
|
this.addCommand({
|
|
id: "excalidraw-convert-image-from-url-to-local-file",
|
|
name: t("CONVERT_URL_TO_FILE"),
|
|
checkCallback: (checking: boolean) => {
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if(!view) return false;
|
|
const img = view.getSingleSelectedImage();
|
|
if(!img || !img.embeddedFile?.isHyperLink) return false;
|
|
if(checking) return true;
|
|
view.convertImageElWithURLToLocalFile(img);
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "excalidraw-unzip-file",
|
|
name: t("UNZIP_CURRENT_FILE"),
|
|
checkCallback: (checking: boolean) => {
|
|
const activeFile = this.app.workspace.getActiveFile();
|
|
if (!activeFile) {
|
|
return false;
|
|
}
|
|
const fileIsExcalidraw = this.isExcalidrawFile(activeFile);
|
|
if (!fileIsExcalidraw) {
|
|
return false;
|
|
}
|
|
|
|
const excalidrawView = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if (excalidrawView) {
|
|
return false;
|
|
}
|
|
|
|
if (checking) {
|
|
return true;
|
|
}
|
|
|
|
(async () => {
|
|
const data = await this.app.vault.read(activeFile);
|
|
const parts = data.split("\n## Drawing\n```compressed-json\n");
|
|
if(parts.length!==2) return;
|
|
const header = parts[0] + "\n## Drawing\n```json\n";
|
|
const compressed = parts[1].split("\n```\n%%");
|
|
if(compressed.length!==2) return;
|
|
const decompressed = decompress(compressed[0]);
|
|
if(!decompressed) {
|
|
new Notice("The compressed string is corrupted. Unable to decompress data.");
|
|
return;
|
|
}
|
|
await this.app.vault.modify(activeFile,header + decompressed + "\n```\n%%" + compressed[1]);
|
|
})();
|
|
|
|
}
|
|
})
|
|
|
|
this.addCommand({
|
|
id: "excalidraw-publish-svg-check",
|
|
name: t("PUBLISH_SVG_CHECK"),
|
|
checkCallback: (checking: boolean) => {
|
|
const publish = this.app.internalPlugins.plugins["publish"].instance;
|
|
if (!publish) {
|
|
return false;
|
|
}
|
|
if (checking) {
|
|
return true;
|
|
}
|
|
(new PublishOutOfDateFilesDialog(this.plugin)).open();
|
|
}
|
|
})
|
|
|
|
this.addCommand({
|
|
id: "excalidraw-embeddable-poroperties",
|
|
name: t("EMBEDDABLE_PROPERTIES"),
|
|
checkCallback: (checking: boolean) => {
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if(!view) return false;
|
|
if(!view.excalidrawAPI) return false;
|
|
const els = view.getViewSelectedElements().filter(el=>el.type==="embeddable") as ExcalidrawEmbeddableElement[];
|
|
if(els.length !== 1) {
|
|
if(checking) return false;
|
|
new Notice("Select a single embeddable element and try again");
|
|
return false;
|
|
}
|
|
if(checking) return true;
|
|
const getFile = (el:ExcalidrawEmbeddableElement):TFile => {
|
|
const res = REGEX_LINK.getRes(el.link).next();
|
|
if(!res || (!res.value && res.done)) {
|
|
return null;
|
|
}
|
|
const link = REGEX_LINK.getLink(res);
|
|
const { file } = processLinkText(link, view);
|
|
return file;
|
|
}
|
|
new EmbeddableSettings(view.plugin,view,getFile(els[0]),els[0]).open();
|
|
}
|
|
})
|
|
|
|
this.addCommand({
|
|
id: "excalidraw-embeddables-relative-scale",
|
|
name: t("EMBEDDABLE_RELATIVE_ZOOM"),
|
|
checkCallback: (checking: boolean) => {
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if(!view) return false;
|
|
if(!view.excalidrawAPI) return false;
|
|
const els = view.getViewSelectedElements().filter(el=>el.type==="embeddable") as ExcalidrawEmbeddableElement[];
|
|
if(els.length === 0) {
|
|
if(checking) return false;
|
|
new Notice("Select at least one embeddable element and try again");
|
|
return false;
|
|
}
|
|
if(checking) return true;
|
|
const ea = getEA(view) as ExcalidrawAutomate;
|
|
const api = ea.getExcalidrawAPI() as ExcalidrawImperativeAPI;
|
|
ea.copyViewElementsToEAforEditing(els);
|
|
const scale = 1/api.getAppState().zoom.value;
|
|
ea.getElements().forEach((el: Mutable<ExcalidrawEmbeddableElement>)=>{
|
|
el.scale = [scale,scale];
|
|
})
|
|
ea.addElementsToView().then(()=>ea.destroy());
|
|
}
|
|
})
|
|
|
|
this.addCommand({
|
|
id: "open-image-excalidraw-source",
|
|
name: t("OPEN_IMAGE_SOURCE"),
|
|
checkCallback: (checking: boolean) => {
|
|
const view = this.app.workspace.getActiveViewOfType(MarkdownView);
|
|
if(!view) return false;
|
|
if(view.leaf !== this.app.workspace.activeLeaf) return false;
|
|
const editor = view.editor;
|
|
if(!editor) return false;
|
|
const cursor = editor.getCursor();
|
|
const line = editor.getLine(cursor.line);
|
|
const fname = extractSVGPNGFileName(line);
|
|
if(!fname) return false;
|
|
const imgFile = this.app.metadataCache.getFirstLinkpathDest(fname, view.file.path);
|
|
if(!imgFile) return false;
|
|
const excalidrawFname = getIMGFilename(imgFile.path, "md");
|
|
let excalidrawFile = this.app.metadataCache.getFirstLinkpathDest(excalidrawFname, view.file.path);
|
|
if(!excalidrawFile) {
|
|
if(excalidrawFname.endsWith(".dark.md")) {
|
|
excalidrawFile = this.app.metadataCache.getFirstLinkpathDest(excalidrawFname.replace(/\.dark\.md$/,".md"), view.file.path);
|
|
}
|
|
if(excalidrawFname.endsWith(".light.md")) {
|
|
excalidrawFile = this.app.metadataCache.getFirstLinkpathDest(excalidrawFname.replace(/\.light\.md$/,".md"), view.file.path);
|
|
}
|
|
if(!excalidrawFile) return false;
|
|
}
|
|
if(checking) return true;
|
|
this.plugin.openDrawing(excalidrawFile, "new-tab", true);
|
|
}
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "excalidraw-disable-autosave",
|
|
name: t("TEMPORARY_DISABLE_AUTOSAVE"),
|
|
checkCallback: (checking) => {
|
|
if(!this.settings.autosave) return false; //already disabled
|
|
if(checking) return true;
|
|
this.settings.autosave = false;
|
|
return true;
|
|
}
|
|
})
|
|
|
|
this.addCommand({
|
|
id: "excalidraw-enable-autosave",
|
|
name: t("TEMPORARY_ENABLE_AUTOSAVE"),
|
|
checkCallback: (checking) => {
|
|
if(this.settings.autosave) return false; //already enabled
|
|
if(checking) return true;
|
|
this.settings.autosave = true;
|
|
return true;
|
|
}
|
|
})
|
|
|
|
this.addCommand({
|
|
id: "excalidraw-download-lib",
|
|
name: t("DOWNLOAD_LIBRARY"),
|
|
callback: ()=>this.plugin.exportLibrary(),
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "excalidraw-open",
|
|
name: t("OPEN_EXISTING_NEW_PANE"),
|
|
callback: () => {
|
|
this.openDialog.start(openDialogAction.openFile, true);
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "excalidraw-open-on-current",
|
|
name: t("OPEN_EXISTING_ACTIVE_PANE"),
|
|
callback: () => {
|
|
this.openDialog.start(openDialogAction.openFile, false);
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "excalidraw-insert-transclusion",
|
|
name: t("TRANSCLUDE"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
return Boolean(this.app.workspace.getActiveViewOfType(MarkdownView))
|
|
}
|
|
this.openDialog.start(openDialogAction.insertLinkToDrawing, false);
|
|
return true;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "excalidraw-insert-last-active-transclusion",
|
|
name: t("TRANSCLUDE_MOST_RECENT"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
return (
|
|
Boolean(this.app.workspace.getActiveViewOfType(MarkdownView)) &&
|
|
this.plugin.lastActiveExcalidrawFilePath !== null
|
|
);
|
|
}
|
|
const file = this.app.vault.getAbstractFileByPath(
|
|
this.plugin.lastActiveExcalidrawFilePath,
|
|
);
|
|
if (!(file instanceof TFile)) {
|
|
return false;
|
|
}
|
|
this.plugin.embedDrawing(file);
|
|
return true;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "excalidraw-autocreate",
|
|
name: t("NEW_IN_NEW_PANE"),
|
|
callback: () => {
|
|
this.plugin.createAndOpenDrawing(getDrawingFilename(this.settings), "new-pane");
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "excalidraw-autocreate-newtab",
|
|
name: t("NEW_IN_NEW_TAB"),
|
|
callback: () => {
|
|
this.plugin.createAndOpenDrawing(getDrawingFilename(this.settings), "new-tab");
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "excalidraw-autocreate-on-current",
|
|
name: t("NEW_IN_ACTIVE_PANE"),
|
|
callback: () => {
|
|
this.plugin.createAndOpenDrawing(getDrawingFilename(this.settings), "active-pane");
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "excalidraw-autocreate-popout",
|
|
name: t("NEW_IN_POPOUT_WINDOW"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
return !DEVICE.isMobile;
|
|
}
|
|
this.plugin.createAndOpenDrawing(getDrawingFilename(this.settings), "popout-window");
|
|
},
|
|
});
|
|
|
|
const insertDrawingToDoc = async (
|
|
location: PaneTarget
|
|
) => {
|
|
const activeView = this.app.workspace.getActiveViewOfType(MarkdownView);
|
|
if (!activeView) {
|
|
return;
|
|
}
|
|
const filename = getEmbedFilename(
|
|
activeView.file.basename,
|
|
this.settings,
|
|
);
|
|
const folder = this.settings.embedUseExcalidrawFolder
|
|
? null
|
|
: (
|
|
await getAttachmentsFolderAndFilePath(
|
|
this.app,
|
|
activeView.file.path,
|
|
filename,
|
|
)
|
|
).folder;
|
|
const file = await this.plugin.createDrawing(filename, folder);
|
|
await this.plugin.embedDrawing(file);
|
|
this.plugin.openDrawing(file, location, true, undefined, true);
|
|
};
|
|
|
|
this.addCommand({
|
|
id: "excalidraw-autocreate-and-embed",
|
|
name: t("NEW_IN_NEW_PANE_EMBED"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
return Boolean(this.app.workspace.getActiveViewOfType(MarkdownView));
|
|
}
|
|
insertDrawingToDoc("new-pane");
|
|
return true;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "excalidraw-autocreate-and-embed-new-tab",
|
|
name: t("NEW_IN_NEW_TAB_EMBED"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
return Boolean(this.app.workspace.getActiveViewOfType(MarkdownView));
|
|
}
|
|
insertDrawingToDoc("new-tab");
|
|
return true;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "excalidraw-autocreate-and-embed-on-current",
|
|
name: t("NEW_IN_ACTIVE_PANE_EMBED"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
return Boolean(this.app.workspace.getActiveViewOfType(MarkdownView));
|
|
}
|
|
insertDrawingToDoc("active-pane");
|
|
return true;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "excalidraw-autocreate-and-embed-popout",
|
|
name: t("NEW_IN_POPOUT_WINDOW_EMBED"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
return !DEVICE.isMobile && Boolean(this.app.workspace.getActiveViewOfType(MarkdownView));
|
|
}
|
|
insertDrawingToDoc("popout-window");
|
|
return true;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "run-ocr",
|
|
name: t("RUN_OCR"),
|
|
checkCallback: (checking: boolean) => {
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if (checking) {
|
|
return (
|
|
Boolean(view)
|
|
);
|
|
}
|
|
if (view) {
|
|
if(!this.settings.taskboneEnabled) {
|
|
new Notice("Taskbone OCR is not enabled. Please go to plugins settings to enable it.",4000);
|
|
return true;
|
|
}
|
|
this.taskbone.getTextForView(view, {forceReScan: false});
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "rerun-ocr",
|
|
name: t("RERUN_OCR"),
|
|
checkCallback: (checking: boolean) => {
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if (checking) {
|
|
return (
|
|
Boolean(view)
|
|
);
|
|
}
|
|
if (view) {
|
|
if(!this.settings.taskboneEnabled) {
|
|
new Notice("Taskbone OCR is not enabled. Please go to plugins settings to enable it.",4000);
|
|
return true;
|
|
}
|
|
this.taskbone.getTextForView(view, {forceReScan: true});
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "run-ocr-selectedelements",
|
|
name: t("RUN_OCR_ELEMENTS"),
|
|
checkCallback: (checking: boolean) => {
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if (checking) {
|
|
return (
|
|
Boolean(view)
|
|
);
|
|
}
|
|
if (view) {
|
|
if(!this.settings.taskboneEnabled) {
|
|
new Notice("Taskbone OCR is not enabled. Please go to plugins settings to enable it.",4000);
|
|
return true;
|
|
}
|
|
this.taskbone.getTextForView(view, {forceReScan: false, selectedElementsOnly: true, addToFrontmatter: false});
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "search-text",
|
|
name: t("SEARCH"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
return (
|
|
Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
|
|
);
|
|
}
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if (view) {
|
|
search(view);
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "fullscreen",
|
|
name: t("TOGGLE_FULLSCREEN"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
return (
|
|
Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
|
|
);
|
|
}
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if (view) {
|
|
if (view.isFullscreen()) {
|
|
view.exitFullscreen();
|
|
} else {
|
|
view.gotoFullscreen();
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "disable-binding",
|
|
name: t("TOGGLE_DISABLEBINDING"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
return (
|
|
Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
|
|
);
|
|
}
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if (view) {
|
|
view.toggleDisableBinding();
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "disable-framerendering",
|
|
name: t("TOGGLE_FRAME_RENDERING"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
return (
|
|
Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
|
|
);
|
|
}
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if (view) {
|
|
view.toggleFrameRendering();
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "frame-settings",
|
|
name: t("FRAME_SETTINGS_TITLE"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
return (
|
|
Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
|
|
);
|
|
}
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if (view) {
|
|
showFrameSettings(getEA(view));
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "copy-link-to-drawing",
|
|
name: t("COPY_DRAWING_LINK"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
return (
|
|
Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
|
|
);
|
|
}
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if (view) {
|
|
navigator.clipboard.writeText(`![[${view.file.path}]]`);
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "disable-frameclipping",
|
|
name: t("TOGGLE_FRAME_CLIPPING"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
return (
|
|
Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
|
|
);
|
|
}
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if (view) {
|
|
view.toggleFrameClipping();
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
});
|
|
|
|
|
|
this.addCommand({
|
|
id: "export-image",
|
|
name: t("EXPORT_IMAGE"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
return (
|
|
Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
|
|
);
|
|
}
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if (view) {
|
|
if(!view.exportDialog) {
|
|
view.exportDialog = new ExportDialog(this.plugin, view,view.file);
|
|
view.exportDialog.createForm();
|
|
}
|
|
view.exportDialog.open();
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
});
|
|
|
|
this.forceSaveCommand = this.addCommand({
|
|
id: "save",
|
|
hotkeys: [{modifiers: ["Ctrl"], key:"s"}], //See also Poposcope
|
|
name: t("FORCE_SAVE"),
|
|
checkCallback: (checking:boolean) => this.plugin.forceSaveActiveView(checking),
|
|
})
|
|
|
|
this.addCommand({
|
|
id: "toggle-lock",
|
|
name: t("TOGGLE_LOCK"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
if (
|
|
Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
|
|
) {
|
|
return !(this.app.workspace.getActiveViewOfType(ExcalidrawView))
|
|
.compatibilityMode;
|
|
}
|
|
return false;
|
|
}
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if (view && !view.compatibilityMode) {
|
|
view.changeTextMode(
|
|
view.textMode === TextMode.parsed ? TextMode.raw : TextMode.parsed,
|
|
);
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "scriptengine-store",
|
|
name: t("INSTALL_SCRIPT_BUTTON"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
return (
|
|
Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
|
|
);
|
|
}
|
|
new ScriptInstallPrompt(this.plugin).open();
|
|
return true;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "delete-file",
|
|
name: t("DELETE_FILE"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
return Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
|
|
}
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if (view) {
|
|
this.ea.reset();
|
|
this.ea.setView(view);
|
|
const el = this.ea.getViewSelectedElement();
|
|
if (el.type !== "image") {
|
|
new Notice(
|
|
"Please select an image or embedded markdown document",
|
|
4000,
|
|
);
|
|
return true;
|
|
}
|
|
const file = this.ea.getViewFileForImageElement(el);
|
|
if (!file) {
|
|
new Notice(
|
|
"Please select an image or embedded markdown document",
|
|
4000,
|
|
);
|
|
return true;
|
|
}
|
|
this.app.vault.delete(file);
|
|
this.ea.deleteViewElements([el]);
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "convert-text2MD",
|
|
name: t("CONVERT_TO_MARKDOWN"),
|
|
checkCallback: (checking: boolean) => {
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView)
|
|
if(!view) return false;
|
|
const selectedTextElements = view.getViewSelectedElements().filter(el=>el.type === "text");
|
|
if(selectedTextElements.length !==1 ) return false;
|
|
const selectedTextElement = selectedTextElements[0] as ExcalidrawTextElement;
|
|
const containerElement = (view.getViewElements() as ExcalidrawElement[]).find(el=>el.id === selectedTextElement.containerId);
|
|
if(containerElement && containerElement.type === "arrow") return false;
|
|
if(checking) return true;
|
|
view.convertTextElementToMarkdown(selectedTextElement, containerElement);
|
|
}
|
|
})
|
|
|
|
this.addCommand({
|
|
id: "insert-link",
|
|
hotkeys: [{ modifiers: ["Mod", "Shift"], key: "k" }],
|
|
name: t("INSERT_LINK"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
return Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
|
|
}
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if (view) {
|
|
this.insertLinkDialog.start(view.file.path, (markdownlink: string, path:string, alias:string) => view.addLink(markdownlink, path, alias));
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "insert-command",
|
|
name: t("INSERT_COMMAND"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
return Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
|
|
}
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if (view) {
|
|
this.insertCommandDialog.start((text: string, fontFamily?: 1 | 2 | 3 | 4, save?: boolean) => view.addText(text, fontFamily, save));
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "insert-link-to-element",
|
|
name: t("INSERT_LINK_TO_ELEMENT_NORMAL"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
return Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
|
|
}
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if (view) {
|
|
view.copyLinkToSelectedElementToClipboard("");
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "insert-link-to-element-group",
|
|
name: t("INSERT_LINK_TO_ELEMENT_GROUP"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
return Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
|
|
}
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if (view) {
|
|
view.copyLinkToSelectedElementToClipboard("group=");
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "insert-link-to-element-frame",
|
|
name: t("INSERT_LINK_TO_ELEMENT_FRAME"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
return Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView));
|
|
}
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if (view) {
|
|
view.copyLinkToSelectedElementToClipboard("frame=");
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "insert-link-to-element-frame-clipped",
|
|
name: t("INSERT_LINK_TO_ELEMENT_FRAME_CLIPPED"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
return Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView));
|
|
}
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if (view) {
|
|
view.copyLinkToSelectedElementToClipboard("clippedframe=");
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "insert-link-to-element-area",
|
|
name: t("INSERT_LINK_TO_ELEMENT_AREA"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
return Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
|
|
}
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if (view) {
|
|
view.copyLinkToSelectedElementToClipboard("area=");
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "toggle-lefthanded-mode",
|
|
name: t("TOGGLE_LEFTHANDED_MODE"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
if(this.app.workspace.getActiveViewOfType(ExcalidrawView)) {
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
const api = view?.excalidrawAPI;
|
|
if(!api) return false;
|
|
const st = api.getAppState();
|
|
if(!st.trayModeEnabled) return false;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
(async()=>{
|
|
const isLeftHanded = this.settings.isLeftHanded;
|
|
await this.plugin.loadSettings({applyLefthandedMode: false});
|
|
this.settings.isLeftHanded = !isLeftHanded;
|
|
this.plugin.saveSettings();
|
|
//not clear why I need to do this. If I don't double apply the stylesheet changes
|
|
//then the style won't be applied in the popout windows
|
|
setLeftHandedMode(!isLeftHanded);
|
|
setTimeout(()=>setLeftHandedMode(!isLeftHanded));
|
|
})()
|
|
return true;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "flip-image",
|
|
name: t("FLIP_IMAGE"),
|
|
checkCallback: (checking:boolean) => {
|
|
if (!DEVICE.isDesktop) return;
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if(!view) return false;
|
|
if(!view.excalidrawAPI) return false;
|
|
const els = view
|
|
.getViewSelectedElements()
|
|
.filter(el=>{
|
|
if(el.type==="image") {
|
|
const ef = view.excalidrawData.getFile(el.fileId);
|
|
if(!ef) {
|
|
return false;
|
|
}
|
|
return this.isExcalidrawFile(ef.file);
|
|
}
|
|
return false;
|
|
});
|
|
if(els.length !== 1) {
|
|
return false;
|
|
}
|
|
if(checking) return true;
|
|
const el = els[0] as ExcalidrawImageElement;
|
|
let ef = view.excalidrawData.getFile(el.fileId);
|
|
this.plugin.forceToOpenInMarkdownFilepath = ef.file?.path;
|
|
const appState = view.excalidrawAPI.getAppState();
|
|
const {x:centerX,y:centerY} = sceneCoordsToViewportCoords({sceneX:el.x+el.width/2,sceneY:el.y+el.height/2},appState);
|
|
const {width, height} = {width:600, height:600};
|
|
const {x,y} = {
|
|
x:Math.max(0,centerX - width/2 + view.ownerWindow.screenX),
|
|
y:Math.max(0,centerY - height/2 + view.ownerWindow.screenY),
|
|
}
|
|
|
|
this.plugin.openDrawing(ef.file, DEVICE.isMobile ? "new-tab":"popout-window", true, undefined, false, {x,y,width,height});
|
|
}
|
|
})
|
|
|
|
this.addCommand({
|
|
id: "duplicate-image",
|
|
name: t("DUPLICATE_IMAGE"),
|
|
checkCallback: (checking:boolean) => {
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if(!view) return false;
|
|
if(!view.excalidrawAPI) return false;
|
|
const els = view.getViewSelectedElements().filter(el=>el.type==="image");
|
|
if(els.length !== 1) {
|
|
if(checking) return false;
|
|
new Notice("Select a single image element and try again");
|
|
return false;
|
|
}
|
|
const el = els[0] as ExcalidrawImageElement;
|
|
const ef = view.excalidrawData.getFile(el.fileId);
|
|
if(!ef?.file) return false;
|
|
if(checking) return true;
|
|
(async()=>{
|
|
const ea = getEA(view) as ExcalidrawAutomate;
|
|
const isAnchored = Boolean(el.customData?.isAnchored);
|
|
const imgId = await ea.addImage(el.x+el.width/5, el.y+el.height/5, ef.file,!isAnchored, isAnchored);
|
|
const img = ea.getElement(imgId) as Mutable<ExcalidrawImageElement>;
|
|
img.width = el.width;
|
|
img.height = el.height;
|
|
if(el.crop) img.crop = {...el.crop};
|
|
const newFileId = fileid() as FileId;
|
|
ea.imagesDict[newFileId] = ea.imagesDict[img.fileId];
|
|
ea.imagesDict[newFileId].id = newFileId;
|
|
delete ea.imagesDict[img.fileId]
|
|
img.fileId = newFileId;
|
|
await ea.addElementsToView(false, false, true);
|
|
ea.selectElementsInView([imgId]);
|
|
ea.destroy();
|
|
})();
|
|
}
|
|
})
|
|
|
|
this.addCommand({
|
|
id: "reset-image-to-100",
|
|
name: t("RESET_IMG_TO_100"),
|
|
checkCallback: (checking:boolean) => {
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if(!view) return false;
|
|
if(!view.excalidrawAPI) return false;
|
|
const els = view.getViewSelectedElements().filter(el=>el.type==="image");
|
|
if(els.length !== 1) {
|
|
if(checking) return false;
|
|
new Notice("Select a single image element and try again");
|
|
return false;
|
|
}
|
|
if(checking) return true;
|
|
|
|
(async () => {
|
|
const el = els[0] as ExcalidrawImageElement;
|
|
let ef = view.excalidrawData.getFile(el.fileId);
|
|
if(!ef) {
|
|
await view.forceSave();
|
|
let ef = view.excalidrawData.getFile(el.fileId);
|
|
new Notice("Select a single image element and try again");
|
|
return false;
|
|
}
|
|
|
|
const ea = new ExcalidrawAutomate(this.plugin,view);
|
|
const size = await ea.getOriginalImageSize(el);
|
|
if(size) {
|
|
ea.copyViewElementsToEAforEditing(els);
|
|
const eaEl = ea.getElement(el.id) as Mutable<ExcalidrawImageElement>;
|
|
if(eaEl.crop) {
|
|
eaEl.width = eaEl.crop.width;
|
|
eaEl.height = eaEl.crop.height;
|
|
} else {
|
|
eaEl.width = size.width; eaEl.height = size.height;
|
|
}
|
|
await ea.addElementsToView(false,false,false);
|
|
}
|
|
ea.destroy();
|
|
})()
|
|
}
|
|
})
|
|
|
|
this.addCommand({
|
|
id: "reset-image-ar",
|
|
name: t("RESET_IMG_ASPECT_RATIO"),
|
|
checkCallback: (checking: boolean) => {
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if (!view) return false;
|
|
if (!view.excalidrawAPI) return false;
|
|
const els = view.getViewSelectedElements().filter(el => el.type === "image");
|
|
if (els.length !== 1) {
|
|
if (checking) return false;
|
|
new Notice("Select a single image element and try again");
|
|
return false;
|
|
}
|
|
if (checking) return true;
|
|
|
|
(async () => {
|
|
const el = els[0] as ExcalidrawImageElement;
|
|
let ef = view.excalidrawData.getFile(el.fileId);
|
|
if (!ef) {
|
|
await view.forceSave();
|
|
let ef = view.excalidrawData.getFile(el.fileId);
|
|
new Notice("Select a single image element and try again");
|
|
return false;
|
|
}
|
|
|
|
const ea = new ExcalidrawAutomate(this.plugin, view);
|
|
if (await ea.resetImageAspectRatio(el)) {
|
|
await ea.addElementsToView(false, false, false);
|
|
}
|
|
ea.destroy();
|
|
})();
|
|
}
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "open-link-props",
|
|
name: t("OPEN_LINK_PROPS"),
|
|
checkCallback: (checking: boolean) => {
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if (!view) return false;
|
|
if (!view.excalidrawAPI) return false;
|
|
const els = view.getViewSelectedElements().filter(el => el.type === "image");
|
|
if (els.length !== 1) {
|
|
if (checking) return false;
|
|
new Notice("Select a single image element and try again");
|
|
return false;
|
|
}
|
|
if (checking) return true;
|
|
|
|
const el = els[0] as ExcalidrawImageElement;
|
|
let ef = view.excalidrawData.getFile(el.fileId);
|
|
let eq = view.excalidrawData.getEquation(el.fileId);
|
|
if (!ef && !eq) {
|
|
view.forceSave();
|
|
new Notice("Please try again.");
|
|
return false;
|
|
}
|
|
|
|
if(ef) {
|
|
view.openEmbeddedLinkEditor(el.id);
|
|
}
|
|
if(eq) {
|
|
view.openLaTeXEditor(el.id);
|
|
}
|
|
}
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "convert-card-to-file",
|
|
name: t("CONVERT_CARD_TO_FILE"),
|
|
checkCallback: (checking:boolean) => {
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if(!view) return false;
|
|
if(!view.excalidrawAPI) return false;
|
|
const els = view.getViewSelectedElements().filter(el=>el.type==="embeddable");
|
|
if(els.length !== 1) {
|
|
if(checking) return false;
|
|
new Notice("Select a single back-of-the-note card and try again");
|
|
return false;
|
|
}
|
|
const embeddableData = view.getEmbeddableLeafElementById(els[0].id);
|
|
const child = embeddableData?.node?.child;
|
|
if(!child || (child.file !== view.file)) {
|
|
if(checking) return false;
|
|
new Notice("The selected embeddable is not a back-of-the-note card.");
|
|
return false;
|
|
}
|
|
if(checking) return true;
|
|
view.moveBackOfTheNoteCardToFile();
|
|
}
|
|
})
|
|
|
|
this.addCommand({
|
|
id: "insert-active-pdfpage",
|
|
name: t("INSERT_ACTIVE_PDF_PAGE_AS_IMAGE"),
|
|
checkCallback: (checking:boolean) => {
|
|
const excalidrawView = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if(!excalidrawView) return false;
|
|
const embeddables = excalidrawView.getViewSelectedElements().filter(el=>el.type==="embeddable");
|
|
if(embeddables.length !== 1) {
|
|
if(checking) return false;
|
|
new Notice("Select a single PDF embeddable and try again");
|
|
return false;
|
|
}
|
|
const isPDF = excalidrawView.getEmbeddableLeafElementById(embeddables[0].id)?.leaf?.view?.getViewType() === "pdf"
|
|
if(!isPDF) return false;
|
|
const page = getActivePDFPageNumberFromPDFView(excalidrawView.getEmbeddableLeafElementById(embeddables[0].id)?.leaf?.view);
|
|
if(!page) return false;
|
|
if(checking) return true;
|
|
|
|
const embeddableEl = embeddables[0] as ExcalidrawEmbeddableElement;
|
|
const ea = new ExcalidrawAutomate(this.plugin,excalidrawView);
|
|
const view = excalidrawView.getEmbeddableLeafElementById(embeddableEl.id)?.leaf?.view;
|
|
const pdfFile: TFile = view && (view instanceof FileView) ? view.file : undefined;
|
|
(async () => {
|
|
const imgID = await ea.addImage(embeddableEl.x + embeddableEl.width + 10, embeddableEl.y, `${pdfFile?.path}#page=${page}`, false, false);
|
|
const imgEl = ea.getElement(imgID) as Mutable<ExcalidrawImageElement>;
|
|
const imageAspectRatio = imgEl.width / imgEl.height;
|
|
if(imageAspectRatio > 1) {
|
|
imgEl.width = embeddableEl.width;
|
|
imgEl.height = embeddableEl.width / imageAspectRatio;
|
|
} else {
|
|
imgEl.height = embeddableEl.height;
|
|
imgEl.width = embeddableEl.height * imageAspectRatio;
|
|
}
|
|
ea.addElementsToView(false, true, true);
|
|
})()
|
|
}
|
|
})
|
|
|
|
this.addCommand({
|
|
id: "crop-image",
|
|
name: t("CROP_IMAGE"),
|
|
checkCallback: (checking:boolean) => {
|
|
const excalidrawView = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
const markdownView = this.app.workspace.getActiveViewOfType(MarkdownView);
|
|
const canvasView:any = this.app.workspace.activeLeaf?.view;
|
|
const isCanvas = canvasView && canvasView.getViewType() === "canvas";
|
|
if(!excalidrawView && !markdownView && !isCanvas) return false;
|
|
|
|
if(excalidrawView) {
|
|
if(!excalidrawView.excalidrawAPI) return false;
|
|
const embeddables = excalidrawView.getViewSelectedElements().filter(el=>el.type==="embeddable");
|
|
const imageEls = excalidrawView.getViewSelectedElements().filter(el=>el.type==="image");
|
|
const isPDF = (imageEls.length === 0 && embeddables.length === 1 && excalidrawView.getEmbeddableLeafElementById(embeddables[0].id)?.leaf?.view?.getViewType() === "pdf")
|
|
const isImage = (imageEls.length === 1 && embeddables.length === 0)
|
|
|
|
if(!isPDF && !isImage) {
|
|
if(checking) return false;
|
|
new Notice("Select a single image element or single PDF embeddable and try again");
|
|
return false;
|
|
}
|
|
|
|
const page = isPDF ? getActivePDFPageNumberFromPDFView(excalidrawView.getEmbeddableLeafElementById(embeddables[0].id)?.leaf?.view) : undefined;
|
|
if(isPDF && !page) {
|
|
return false;
|
|
}
|
|
|
|
if(checking) return true;
|
|
|
|
if(isPDF) {
|
|
const embeddableEl = embeddables[0] as ExcalidrawEmbeddableElement;
|
|
const ea = new ExcalidrawAutomate(this.plugin,excalidrawView);
|
|
const view = excalidrawView.getEmbeddableLeafElementById(embeddableEl.id)?.leaf?.view;
|
|
const pdfFile: TFile = view && (view instanceof FileView) ? view.file : undefined;
|
|
carveOutPDF(ea, embeddableEl, `${pdfFile?.path}#page=${page}`, pdfFile);
|
|
return;
|
|
}
|
|
|
|
const imageEl = imageEls[0] as ExcalidrawImageElement;
|
|
(async () => {
|
|
let ef = excalidrawView.excalidrawData.getFile(imageEl.fileId);
|
|
|
|
if(!ef) {
|
|
await excalidrawView.save();
|
|
await sleep(500);
|
|
ef = excalidrawView.excalidrawData.getFile(imageEl.fileId);
|
|
if(!ef) {
|
|
new Notice("Select a single image element and try again");
|
|
return false;
|
|
}
|
|
}
|
|
const ea = new ExcalidrawAutomate(this.plugin,excalidrawView);
|
|
carveOutImage(ea, imageEl);
|
|
})();
|
|
}
|
|
|
|
const carveout = async (isFile: boolean, sourceFile: TFile, imageFile: TFile, imageURL: string, replacer: Function, ref?: string) => {
|
|
const ea = getEA() as ExcalidrawAutomate;
|
|
const imageID = await ea.addImage(
|
|
0, 0,
|
|
isFile
|
|
? ((isFile && imageFile.extension === "pdf" && ref) ? `${imageFile.path}#${ref}` : imageFile)
|
|
: imageURL,
|
|
false, false
|
|
);
|
|
if(!imageID) {
|
|
new Notice(`Can't load image\n\n${imageURL}`);
|
|
return;
|
|
}
|
|
|
|
let fnBase = "";
|
|
let imageLink = "";
|
|
if(isFile) {
|
|
fnBase = imageFile.basename;
|
|
imageLink = ref
|
|
? `[[${imageFile.path}#${ref}]]`
|
|
: `[[${imageFile.path}]]`;
|
|
} else {
|
|
imageLink = imageURL;
|
|
const imagename = imageURL.match(/^.*\/([^?]*)\??.*$/)?.[1];
|
|
fnBase = imagename.substring(0,imagename.lastIndexOf("."));
|
|
}
|
|
|
|
const {folderpath, filename} = await getCropFileNameAndFolder(this.plugin,sourceFile.path,fnBase)
|
|
const newFile = await createImageCropperFile(ea,imageID,imageLink,folderpath,filename);
|
|
ea.destroy();
|
|
if(!newFile) return;
|
|
const link = this.app.metadataCache.fileToLinktext(newFile,sourceFile.path, true);
|
|
replacer(link, newFile);
|
|
}
|
|
|
|
if(isCanvas) {
|
|
const selectedNodes:any = [];
|
|
canvasView.canvas.nodes.forEach((node:any) => {
|
|
if(node.nodeEl.hasClass("is-focused")) selectedNodes.push(node);
|
|
})
|
|
if(selectedNodes.length !== 1) return false;
|
|
const node = selectedNodes[0];
|
|
let extension = "";
|
|
let isExcalidraw = false;
|
|
if(node.file) {
|
|
extension = node.file.extension;
|
|
isExcalidraw = this.isExcalidrawFile(node.file);
|
|
}
|
|
if(node.url) {
|
|
extension = getURLImageExtension(node.url);
|
|
}
|
|
const page = extension === "pdf" ? getActivePDFPageNumberFromPDFView(node?.child) : undefined;
|
|
if(!page && !IMAGE_TYPES.contains(extension) && !isExcalidraw) return false;
|
|
if(checking) return true;
|
|
|
|
const replacer = (link:string, file: TFile) => {
|
|
if(node.file) {
|
|
(node.file.extension === "pdf")
|
|
? node.canvas.createFileNode({pos:{x:node.x + node.width + 10,y: node.y}, file})
|
|
: node.setFile(file);
|
|
}
|
|
if(node.url) {
|
|
node.canvas.createFileNode({pos:{x:node.x + 20,y: node.y+20}, file});
|
|
}
|
|
}
|
|
carveout(Boolean(node.file), canvasView.file, node.file, node.url, replacer, page ? `page=${page}` : undefined);
|
|
}
|
|
|
|
if (markdownView) {
|
|
const editor = markdownView.editor;
|
|
const cursor = editor.getCursor();
|
|
const line = editor.getLine(cursor.line);
|
|
const parts = REGEX_LINK.getResList(line);
|
|
if(parts.length === 0) return false;
|
|
let imgpath = REGEX_LINK.getLink(parts[0]);
|
|
const isWikilink = REGEX_LINK.isWikiLink(parts[0]);
|
|
let alias = REGEX_LINK.getAliasOrLink(parts[0]);
|
|
if(alias === imgpath) alias = null;
|
|
imgpath = decodeURI(imgpath);
|
|
const imagePathParts = imgpath.split("#");
|
|
const hasRef = imagePathParts.length === 2;
|
|
const imageFile = this.app.metadataCache.getFirstLinkpathDest(
|
|
hasRef ? imagePathParts[0] : imgpath,
|
|
markdownView.file.path
|
|
);
|
|
const isFile = (imageFile && imageFile instanceof TFile);
|
|
const isExcalidraw = isFile ? this.isExcalidrawFile(imageFile) : false;
|
|
let imagepath = isFile ? imageFile.path : "";
|
|
let extension = isFile ? imageFile.extension : "";
|
|
if(imgpath.match(/^https?|file/)) {
|
|
imagepath = imgpath;
|
|
extension = getURLImageExtension(imgpath);
|
|
}
|
|
if(imagepath === "") return false;
|
|
if(extension !== "pdf" && !IMAGE_TYPES.contains(extension) && !isExcalidraw) return false;
|
|
if(checking) return true;
|
|
const ref = imagePathParts[1];
|
|
const replacer = (link:string) => {
|
|
const lineparts = line.split(parts[0].value[0])
|
|
const pdfLink = isFile && ref
|
|
? "\n" + getLink(this.plugin ,{
|
|
embed: false,
|
|
alias: alias ?? `${imageFile.basename}, ${ref.replace("="," ")}`,
|
|
path:`${imageFile.path}#${ref}`
|
|
}, isWikilink)
|
|
: "";
|
|
editor.setLine(cursor.line,lineparts[0] + getLink(this.plugin ,{embed: true, path:link, alias}, isWikilink) + pdfLink + lineparts[1]);
|
|
}
|
|
carveout(isFile, markdownView.file, imageFile, imagepath, replacer, ref);
|
|
}
|
|
}
|
|
})
|
|
|
|
this.addCommand({
|
|
id: "annotate-image",
|
|
name: t("ANNOTATE_IMAGE"),
|
|
checkCallback: (checking:boolean) => {
|
|
const markdownView = this.app.workspace.getActiveViewOfType(MarkdownView);
|
|
const canvasView:any = this.app.workspace.activeLeaf?.view;
|
|
const isCanvas = canvasView && canvasView.getViewType() === "canvas";
|
|
if(!markdownView && !isCanvas) return false;
|
|
|
|
const carveout = async (isFile: boolean, sourceFile: TFile, imageFile: TFile, imageURL: string, replacer: Function, ref?: string) => {
|
|
const ea = getEA() as ExcalidrawAutomate;
|
|
const imageID = await ea.addImage(
|
|
0, 0,
|
|
isFile
|
|
? ((isFile && imageFile.extension === "pdf" && ref) ? `${imageFile.path}#${ref}` : imageFile)
|
|
: imageURL,
|
|
false, false
|
|
);
|
|
if(!imageID) {
|
|
new Notice(`Can't load image\n\n${imageURL}`);
|
|
ea.destroy();
|
|
return;
|
|
}
|
|
const el = ea.getElement(imageID) as Mutable<ExcalidrawImageElement>;
|
|
el.locked = true;
|
|
const size = this.settings.annotatePreserveSize
|
|
? await getImageSize(ea.imagesDict[el.fileId].dataURL)
|
|
: null;
|
|
let fnBase = "";
|
|
let imageLink = "";
|
|
if(isFile) {
|
|
fnBase = imageFile.basename;
|
|
imageLink = ref
|
|
? `[[${imageFile.path}#${ref}]]`
|
|
: `[[${imageFile.path}]]`;
|
|
} else {
|
|
imageLink = imageURL;
|
|
const imagename = imageURL.match(/^.*\/([^?]*)\??.*$/)?.[1];
|
|
fnBase = imagename.substring(0,imagename.lastIndexOf("."));
|
|
}
|
|
|
|
let template:TFile;
|
|
const templates = getListOfTemplateFiles(this.plugin);
|
|
if(templates) {
|
|
template = await templatePromt(templates, this.app);
|
|
}
|
|
|
|
const {folderpath, filename} = await getAnnotationFileNameAndFolder(this.plugin,sourceFile.path,fnBase)
|
|
const newPath = await ea.create ({
|
|
templatePath: template?.path,
|
|
filename,
|
|
foldername: folderpath,
|
|
onNewPane: true,
|
|
frontmatterKeys: {
|
|
...this.settings.matchTheme ? {"excalidraw-export-dark": isObsidianThemeDark()} : {},
|
|
...(imageFile.extension === "pdf") ? {"cssclasses": "excalidraw-cropped-pdfpage"} : {},
|
|
}
|
|
});
|
|
ea.destroy();
|
|
|
|
//wait for file to be created/indexed by Obsidian
|
|
let newFile = this.app.vault.getAbstractFileByPath(newPath);
|
|
let counter = 0;
|
|
while((!newFile || !this.isExcalidrawFile(newFile as TFile)) && counter < 50) {
|
|
await sleep(100);
|
|
newFile = this.app.vault.getAbstractFileByPath(newPath);
|
|
counter++;
|
|
}
|
|
//console.log({counter, file});
|
|
if(!newFile || !(newFile instanceof TFile)) {
|
|
new Notice("File not found. NewExcalidraw Drawing is taking too long to create. Please try again.");
|
|
return;
|
|
}
|
|
|
|
if(!newFile) return;
|
|
const link = this.app.metadataCache.fileToLinktext(newFile,sourceFile.path, true);
|
|
replacer(link, newFile, size ? `${size.width}` : null);
|
|
}
|
|
|
|
if(isCanvas) {
|
|
const selectedNodes:any = [];
|
|
canvasView.canvas.nodes.forEach((node:any) => {
|
|
if(node.nodeEl.hasClass("is-focused")) selectedNodes.push(node);
|
|
})
|
|
if(selectedNodes.length !== 1) return false;
|
|
const node = selectedNodes[0];
|
|
let extension = "";
|
|
let isExcalidraw = false;
|
|
if(node.file) {
|
|
extension = node.file.extension;
|
|
isExcalidraw = this.isExcalidrawFile(node.file);
|
|
}
|
|
if(node.url) {
|
|
extension = getURLImageExtension(node.url);
|
|
}
|
|
const page = extension === "pdf" ? getActivePDFPageNumberFromPDFView(node?.child) : undefined;
|
|
if(!page && !IMAGE_TYPES.contains(extension) && !isExcalidraw) return false;
|
|
if(checking) return true;
|
|
|
|
const replacer = (link:string, file: TFile) => {
|
|
if(node.file) {
|
|
(node.file.extension === "pdf")
|
|
? node.canvas.createFileNode({pos:{x:node.x + node.width + 10,y: node.y}, file})
|
|
: node.setFile(file);
|
|
}
|
|
if(node.url) {
|
|
node.canvas.createFileNode({pos:{x:node.x + 20,y: node.y+20}, file});
|
|
}
|
|
}
|
|
carveout(Boolean(node.file), canvasView.file, node.file, node.url, replacer, page ? `page=${page}` : undefined);
|
|
}
|
|
|
|
if (markdownView) {
|
|
const editor = markdownView.editor;
|
|
const cursor = editor.getCursor();
|
|
const line = editor.getLine(cursor.line);
|
|
const parts = REGEX_LINK.getResList(line);
|
|
if(parts.length === 0) return false;
|
|
let imgpath = REGEX_LINK.getLink(parts[0]);
|
|
const isWikilink = REGEX_LINK.isWikiLink(parts[0]);
|
|
let alias = REGEX_LINK.getAliasOrLink(parts[0]);
|
|
if(alias === imgpath) alias = null;
|
|
imgpath = decodeURI(imgpath);
|
|
const imagePathParts = imgpath.split("#");
|
|
const hasRef = imagePathParts.length === 2;
|
|
const imageFile = this.app.metadataCache.getFirstLinkpathDest(
|
|
hasRef ? imagePathParts[0] : imgpath,
|
|
markdownView.file.path
|
|
);
|
|
const isFile = (imageFile && imageFile instanceof TFile);
|
|
const isExcalidraw = isFile ? this.isExcalidrawFile(imageFile) : false;
|
|
let imagepath = isFile ? imageFile.path : "";
|
|
let extension = isFile ? imageFile.extension : "";
|
|
if(imgpath.match(/^https?|file/)) {
|
|
imagepath = imgpath;
|
|
extension = getURLImageExtension(imgpath);
|
|
}
|
|
if(imagepath === "") return false;
|
|
if(extension !== "pdf" && !IMAGE_TYPES.contains(extension) && !isExcalidraw) return false;
|
|
if(checking) return true;
|
|
const ref = imagePathParts[1];
|
|
const replacer = (link:string, _:TFile, size:string) => {
|
|
const lineparts = line.split(parts[0].value[0])
|
|
const pdfLink = isFile && ref
|
|
? "\n" + getLink(this.plugin ,{
|
|
embed: false,
|
|
alias: getAliasWithSize(alias ?? `${imageFile.basename}, ${ref.replace("="," ")}`,size),
|
|
path:`${imageFile.path}#${ref}`
|
|
}, isWikilink)
|
|
: "";
|
|
editor.setLine(
|
|
cursor.line,
|
|
lineparts[0] + getLink(this.plugin ,{embed: true, path:link, alias: getAliasWithSize(alias,size)}, isWikilink) + pdfLink + lineparts[1]
|
|
);
|
|
}
|
|
carveout(isFile, markdownView.file, imageFile, imagepath, replacer, ref);
|
|
}
|
|
}
|
|
})
|
|
|
|
this.addCommand({
|
|
id: "insert-image",
|
|
name: t("INSERT_IMAGE"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
return Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
|
|
}
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if (view) {
|
|
this.insertImageDialog.start(view);
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "import-svg",
|
|
name: t("IMPORT_SVG"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
return Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
|
|
}
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if (view) {
|
|
this.importSVGDialog.start(view);
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "release-notes",
|
|
name: t("READ_RELEASE_NOTES"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
return Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
|
|
}
|
|
new ReleaseNotes(this.app, this.plugin, PLUGIN_VERSION).open();
|
|
return true;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "tray-mode",
|
|
name: t("TRAY_MODE"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if (!view || !view.excalidrawAPI) {
|
|
return false;
|
|
}
|
|
const st = view.excalidrawAPI.getAppState();
|
|
if (st.zenModeEnabled || st.viewModeEnabled) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if (view && view.excalidrawAPI) {
|
|
view.toggleTrayMode();
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "insert-md",
|
|
name: t("INSERT_MD"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
return Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
|
|
}
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if (view) {
|
|
this.insertMDDialog.start(view);
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "insert-pdf",
|
|
name: t("INSERT_PDF"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
return Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
|
|
}
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if (view) {
|
|
const insertPDFModal = new InsertPDFModal(this.plugin, view);
|
|
insertPDFModal.open();
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "insert-pdf",
|
|
name: t("INSERT_LAST_ACTIVE_PDF_PAGE_AS_IMAGE"),
|
|
checkCallback: (checking: boolean) => {
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if(!Boolean(view)) return false;
|
|
const PDFLink = this.plugin.getLastActivePDFPageLink(view.file);
|
|
if(!PDFLink) return false;
|
|
if(checking) return true;
|
|
const ea = getEA(view);
|
|
insertImageToView(
|
|
ea,
|
|
view.currentPosition,
|
|
PDFLink,
|
|
undefined,
|
|
undefined,
|
|
true,
|
|
);
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "universal-add-file",
|
|
name: t("UNIVERSAL_ADD_FILE"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
return Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
|
|
}
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if (view) {
|
|
const insertFileModal = new UniversalInsertFileModal(this.plugin, view);
|
|
insertFileModal.open();
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "universal-card",
|
|
name: t("INSERT_CARD"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
return Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
|
|
}
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if (view) {
|
|
view.insertBackOfTheNoteCard();
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "insert-LaTeX-symbol",
|
|
name: t("INSERT_LATEX"),
|
|
checkCallback: (checking: boolean) => {
|
|
if (checking) {
|
|
return Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView));
|
|
}
|
|
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
|
if (view) {
|
|
insertLaTeXToView(view);
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "toggle-excalidraw-view",
|
|
name: t("TOGGLE_MODE"),
|
|
checkCallback: (checking) => {
|
|
const activeFile = this.app.workspace.getActiveFile();
|
|
if (!activeFile) {
|
|
return false;
|
|
}
|
|
const fileIsExcalidraw = this.isExcalidrawFile(activeFile);
|
|
|
|
if (checking) {
|
|
if (
|
|
Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
|
|
) {
|
|
return !(this.app.workspace.getActiveViewOfType(ExcalidrawView))
|
|
.compatibilityMode;
|
|
}
|
|
return fileIsExcalidraw;
|
|
}
|
|
|
|
const excalidrawView = this.app.workspace.getActiveViewOfType(ExcalidrawView)
|
|
if (excalidrawView) {
|
|
excalidrawView.openAsMarkdown();
|
|
return;
|
|
}
|
|
|
|
const markdownView = this.app.workspace.getActiveViewOfType(MarkdownView)
|
|
if (markdownView && fileIsExcalidraw) {
|
|
(async()=>{
|
|
await markdownView.save();
|
|
const activeLeaf = markdownView.leaf;
|
|
this.plugin.excalidrawFileModes[(activeLeaf as any).id || activeFile.path] =
|
|
VIEW_TYPE_EXCALIDRAW;
|
|
setExcalidrawView(activeLeaf);
|
|
})()
|
|
return;
|
|
}
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "convert-to-excalidraw",
|
|
name: t("CONVERT_NOTE_TO_EXCALIDRAW"),
|
|
checkCallback: (checking) => {
|
|
const activeFile = this.app.workspace.getActiveFile();
|
|
const activeView = this.app.workspace.getActiveViewOfType(MarkdownView);
|
|
|
|
if (!activeFile || !activeView) {
|
|
return false;
|
|
}
|
|
|
|
if(this.isExcalidrawFile(activeFile)) {
|
|
return false;
|
|
}
|
|
|
|
if(checking) {
|
|
return true;
|
|
}
|
|
|
|
(async () => {
|
|
await activeView.save();
|
|
const template = await this.plugin.getBlankDrawing();
|
|
const target = await this.app.vault.read(activeFile);
|
|
const mergedTarget = mergeMarkdownFiles(template, target);
|
|
await this.app.vault.modify(
|
|
activeFile,
|
|
mergedTarget,
|
|
);
|
|
setExcalidrawView(activeView.leaf);
|
|
})();
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "convert-excalidraw",
|
|
name: t("CONVERT_EXCALIDRAW"),
|
|
checkCallback: (checking) => {
|
|
if (checking) {
|
|
const files = this.app.vault
|
|
.getFiles()
|
|
.filter((f) => f.extension == "excalidraw");
|
|
return files.length > 0;
|
|
}
|
|
this.plugin.convertExcalidrawToMD();
|
|
return true;
|
|
},
|
|
});
|
|
}
|
|
} |