diff --git a/manifest.json b/manifest.json index f4517af..2870525 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "obsidian-excalidraw-plugin", "name": "Excalidraw", - "version": "1.4.3", + "version": "1.4.4", "minAppVersion": "0.12.16", "description": "An Obsidian plugin to edit and view Excalidraw drawings", "author": "Zsolt Viczian", diff --git a/src/ExcalidrawAutomate.ts b/src/ExcalidrawAutomate.ts index b85fc9b..e19de1a 100644 --- a/src/ExcalidrawAutomate.ts +++ b/src/ExcalidrawAutomate.ts @@ -868,7 +868,7 @@ async function getTemplate(plugin: ExcalidrawPlugin, fileWithPath:string, loadFi if(trimLocation == -1) trimLocation = data.search("# Drawing\n"); if(loadFiles) { - await loadSceneFiles(plugin,excalidrawData.files, excalidrawData.equations, null, (fileArray:any, view:any)=>{ + await loadSceneFiles(plugin,excalidrawData, null, (fileArray:any, view:any)=>{ for(const f of fileArray) { excalidrawData.scene.files[f.id] = f; } diff --git a/src/ExcalidrawData.ts b/src/ExcalidrawData.ts index 2370998..adb3b4d 100644 --- a/src/ExcalidrawData.ts +++ b/src/ExcalidrawData.ts @@ -113,8 +113,8 @@ export class ExcalidrawData { private textMode: TextMode = TextMode.raw; private plugin: ExcalidrawPlugin; public loaded: boolean = false; - public files:Map = null; //fileId, path - public equations:Map = null; //fileId, path + private files:Map = null; //fileId, path + private equations:Map = null; //fileId, path private compatibilityMode:boolean = false; constructor(plugin: ExcalidrawPlugin) { @@ -215,14 +215,14 @@ export class ExcalidrawData { const REG_FILEID_FILEPATH = /([\w\d]*):\s*\[\[([^\]]*)]]\n/gm; res = data.matchAll(REG_FILEID_FILEPATH); while(!(parts = res.next()).done) { - this.files.set(parts.value[1] as FileId,parts.value[2]); + this.setFile(parts.value[1] as FileId,parts.value[2]); } //Load Equations const REG_FILEID_EQUATION = /([\w\d]*):\s*\$\$(.*)(\$\$\s*\n)/gm; res = data.matchAll(REG_FILEID_EQUATION); while(!(parts = res.next()).done) { - this.equations.set(parts.value[1] as FileId,parts.value[2]); + this.setEquation(parts.value[1] as FileId,parts.value[2]); } //Check to see if there are text elements in the JSON that were missed from the # Text Elements section @@ -556,7 +556,7 @@ export class ExcalidrawData { if(!scene.files || scene.files == {}) return false; for(const key of Object.keys(scene.files)) { - if(!(this.files.has(key as FileId) || this.equations.has(key as FileId))) { + if(!(this.hasFile(key as FileId) || this.hasEquation(key as FileId))) { dirty = true; let fname = "Pasted Image "+window.moment().format("YYYYMMDDHHmmss_SSS"); switch(scene.files[key].mimeType) { @@ -568,7 +568,7 @@ export class ExcalidrawData { } const [folder,filepath] = await getAttachmentsFolderAndFilePath(this.app,this.file.path,fname); await this.app.vault.createBinary(filepath,getBinaryFileFromDataURL(scene.files[key].dataURL)); - this.files.set(key as FileId,filepath); + this.setFile(key as FileId,filepath); } } return dirty; @@ -663,4 +663,74 @@ export class ExcalidrawData { return showLinkBrackets != this.showLinkBrackets; } + + /* + // Files and equations copy/paste support + // This is not a complete solution, it assumes the source document is opened first + // at that time the fileId is stored in the master files/equations map + // when pasted the map is checked if the file already exists + // This will not work if pasting from one vault to another, but for the most common usecase + // of copying an image or equation from one drawing to another within the same vault + // this is going to do the job + */ + public setFile(fileId:FileId, path:string) { + //always store absolute path because in case of paste, relative path may not resolve ok + const file = this.app.metadataCache.getFirstLinkpathDest(path,this.file.path); + const p = file?.path ?? path; + this.files.set(fileId,p); + this.plugin.filesMaster.set(fileId,p); + } + + public getFile(fileId:FileId) { + return this.files.get(fileId); + } + + public getFileEntries() { + return this.files.entries(); + } + + public deleteFile(fileId:FileId) { + this.files.delete(fileId); + //deliberately not deleting from plugin.filesMaster + //could be present in other drawings as well + } + + //Image copy/paste support + public hasFile(fileId:FileId):boolean { + if(this.files.has(fileId)) return true; + if(this.plugin.filesMaster.has(fileId)) { + this.files.set(fileId,this.plugin.filesMaster.get(fileId)); + return true; + } + return false; + } + + public setEquation(fileId:FileId, equation:string) { + this.equations.set(fileId,equation); + this.plugin.equationsMaster.set(fileId,equation); + } + + public getEquation(fileId: FileId) { + return this.equations.get(fileId); + } + + public getEquationEntries() { + return this.equations.entries(); + } + + public deleteEquation(fileId:FileId) { + this.equations.delete(fileId); + //deliberately not deleting from plugin.equationsMaster + //could be present in other drawings as well + } + + //Image copy/paste support + public hasEquation(fileId:FileId):boolean { + if(this.equations.has(fileId)) return true; + if(this.plugin.equationsMaster.has(fileId)) { + this.equations.set(fileId,this.plugin.equationsMaster.get(fileId)); + return true; + } + return false; + } } \ No newline at end of file diff --git a/src/ExcalidrawView.ts b/src/ExcalidrawView.ts index 6bf00a9..529cb41 100644 --- a/src/ExcalidrawView.ts +++ b/src/ExcalidrawView.ts @@ -269,20 +269,20 @@ export default class ExcalidrawView extends TextFileView { } else { const selectedImage = this.getSelectedImageElement(); if(selectedImage?.id) { - if(this.excalidrawData.equations.has(selectedImage.fileId)) { - const equation = this.excalidrawData.equations.get(selectedImage.fileId); + if(this.excalidrawData.hasEquation(selectedImage.fileId)) { + const equation = this.excalidrawData.getEquation(selectedImage.fileId); const prompt = new Prompt(this.app, t("ENTER_LATEX"),equation,''); prompt.openAndGetValue( async (formula:string)=> { if(!formula) return; - this.excalidrawData.equations.set(selectedImage.fileId,formula); + this.excalidrawData.setEquation(selectedImage.fileId,formula); await this.save(true); await updateEquation(formula,selectedImage.fileId,this,addFiles); }); return; } await this.save(true); //in case pasted images haven't been saved yet - if(this.excalidrawData.files.has(selectedImage.fileId)) { - linkText = this.excalidrawData.files.get(selectedImage.fileId); + if(this.excalidrawData.hasFile(selectedImage.fileId)) { + linkText = this.excalidrawData.getFile(selectedImage.fileId); } } } @@ -471,8 +471,7 @@ export default class ExcalidrawView extends TextFileView { } loadSceneFiles( this.plugin, - this.excalidrawData.files, - this.excalidrawData.equations, + this.excalidrawData, this, (files:any, view:ExcalidrawView) => addFiles(files,view), this.file?.path @@ -659,8 +658,7 @@ export default class ExcalidrawView extends TextFileView { this.excalidrawAPI = api; loadSceneFiles( this.plugin, - this.excalidrawData.files, - this.excalidrawData.equations, + this.excalidrawData, this, (files:any, view:ExcalidrawView)=>addFiles(files,view), this.file?.path @@ -785,10 +783,10 @@ export default class ExcalidrawView extends TextFileView { created: images[k].created }); if(images[k].file) { - this.excalidrawData.files.set(images[k].id,images[k].file); + this.excalidrawData.setFile(images[k].id,images[k].file); } if(images[k].tex) { - this.excalidrawData.equations.set(images[k].id,images[k].tex); + this.excalidrawData.setEquation(images[k].id,images[k].tex); } }); this.excalidrawAPI.addFiles(files); diff --git a/src/Utils.ts b/src/Utils.ts index 75ba818..7aebb66 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -9,6 +9,7 @@ import ExcalidrawView, { ExportSettings } from "./ExcalidrawView"; import { ExcalidrawSettings } from "./settings"; import { html_beautify } from "js-beautify"; import html2canvas from "html2canvas"; +import { ExcalidrawData } from "./ExcalidrawData"; declare module "obsidian" { interface Workspace { @@ -371,18 +372,17 @@ export const embedFontsInSVG = (svg:SVGSVGElement):SVGSVGElement => { export const loadSceneFiles = async ( plugin:ExcalidrawPlugin, - filesMap: Map, - equationsMap: Map, + excalidrawData: ExcalidrawData, view: ExcalidrawView, addFiles:Function, sourcePath:string ) => { const app = plugin.app; - let entries = filesMap.entries(); + let entries = excalidrawData.getFileEntries(); let entry; let files:BinaryFileData[] = []; while(!(entry = entries.next()).done) { - const file = app.metadataCache.getFirstLinkpathDest(entry.value[1],sourcePath) + const file = app.metadataCache.getFirstLinkpathDest(entry.value[1],sourcePath); if(file && file instanceof TFile) { const data = await getObsidianImage(plugin,file); files.push({ @@ -396,7 +396,7 @@ export const loadSceneFiles = async ( } } - entries = equationsMap.entries(); + entries = excalidrawData.getEquationEntries(); while(!(entry = entries.next()).done) { const tex = entry.value[1]; const data = await tex2dataURL(tex); diff --git a/src/main.ts b/src/main.ts index ad49b84..96d0402 100644 --- a/src/main.ts +++ b/src/main.ts @@ -62,6 +62,7 @@ import { around } from "monkey-around"; import { t } from "./lang/helpers"; import { checkAndCreateFolder, download, embedFontsInSVG, generateSVGString, getAttachmentsFolderAndFilePath, getIMGPathFromExcalidrawFile, getNewUniqueFilepath, getPNG, getSVG, isObsidianThemeDark, splitFolderAndFilename, svgToBase64 } from "./Utils"; import { OneOffs } from "./OneOffs"; +import { FileId } from "@zsviczian/excalidraw/types/element/types"; declare module "obsidian" { interface App { @@ -86,9 +87,14 @@ export default class ExcalidrawPlugin extends Plugin { private fileExplorerObserver: MutationObserver; public opencount:number = 0; public ea:ExcalidrawAutomate; + //A master list of fileIds to facilitate copy / paste + public filesMaster:Map = null; //fileId, path + public equationsMaster:Map = null; //fileId, formula constructor(app: App, manifest: PluginManifest) { super(app, manifest); + this.filesMaster = new Map(); + this.equationsMaster = new Map(); } async onload() { diff --git a/versions.json b/versions.json index d3ea25d..467c6bb 100644 --- a/versions.json +++ b/versions.json @@ -1,4 +1,4 @@ { - "1.4.3": "0.12.16", + "1.4.4": "0.12.16", "1.4.2": "0.11.13" }