From ae4f4b4f08f31d0fc2fb6bb0abd595227f4eb414 Mon Sep 17 00:00:00 2001 From: zsviczian Date: Tue, 14 May 2024 21:07:42 +0200 Subject: [PATCH] 2.1.8.1-beta-1 --- manifest-beta.json | 2 +- src/CodeMirrorExtension/Fadeout.ts | 13 ++- src/ExcalidrawAutomate.ts | 10 +- src/ExcalidrawData.ts | 162 ++++++++++++++++++++++------- src/constants/constants.ts | 13 ++- src/lang/locale/en.ts | 1 + src/main.ts | 57 ++++++---- src/types.d.ts | 14 +++ src/utils/ObsidianUtils.ts | 19 +++- 9 files changed, 215 insertions(+), 76 deletions(-) diff --git a/manifest-beta.json b/manifest-beta.json index 8857dfe..768f102 100644 --- a/manifest-beta.json +++ b/manifest-beta.json @@ -1,7 +1,7 @@ { "id": "obsidian-excalidraw-plugin", "name": "Excalidraw", - "version": "2.1.6.1-beta-1", + "version": "2.1.8.1-beta-1", "minAppVersion": "1.1.6", "description": "An Obsidian plugin to edit and view Excalidraw drawings", "author": "Zsolt Viczian", diff --git a/src/CodeMirrorExtension/Fadeout.ts b/src/CodeMirrorExtension/Fadeout.ts index d64fd8a..529afe4 100644 --- a/src/CodeMirrorExtension/Fadeout.ts +++ b/src/CodeMirrorExtension/Fadeout.ts @@ -10,9 +10,10 @@ const o0 = Decoration.line({ attributes: {class: "ex-opacity-0"} }); export const HideTextBetweenCommentsExtension = ViewPlugin.fromClass( class { view: EditorView; - decorations: DecorationSet; + decorations: DecorationSet; + reExcalidrawData = /^%%(?:\r\n|\r|\n)# Excalidraw Data$/gm; reTextElements = /^%%(?:\r\n|\r|\n)# Text Elements$/gm; - reDrawing = /^%%(?:\r\n|\r|\n)# Drawing$/gm; + reDrawing = /^%%(?:\r\n|\r|\n)##? Drawing$/gm; linecount = 0; isExcalidraw = false; @@ -32,11 +33,15 @@ export const HideTextBetweenCommentsExtension = ViewPlugin.fromClass( const text = doc.toString(); - let start = text.search(this.reTextElements); + let start = text.search(this.reExcalidrawData); + if(start == -1) { + start = text.search(this.reTextElements); + } if(start == -1) { start = text.search(this.reDrawing); - if(start == -1) return Decoration.none; } + if(start == -1) return Decoration.none; + const startLine = doc.lineAt(start).number; const endLine = doc.lines; let builder = new RangeSetBuilder() diff --git a/src/ExcalidrawAutomate.ts b/src/ExcalidrawAutomate.ts index 6206cb4..db4fca1 100644 --- a/src/ExcalidrawAutomate.ts +++ b/src/ExcalidrawAutomate.ts @@ -35,8 +35,6 @@ import { REG_LINKINDEX_INVALIDCHARS, THEME_FILTER, mermaidToExcalidraw, - MD_TEXTELEMENTS, - MD_DRAWING, } from "src/constants/constants"; import { blobToBase64, checkAndCreateFolder, getDrawingFilename, getExcalidrawEmbeddedFilesFiletree, getListOfTemplateFiles, getNewUniqueFilepath, hasExcalidrawEmbeddedImagesTreeChanged, } from "src/utils/FileUtils"; import { @@ -720,7 +718,7 @@ export class ExcalidrawAutomate { const generateMD = ():string => { const textElements = this.getElements().filter(el => el.type === "text") as ExcalidrawTextElement[]; - let outString = `${MD_TEXTELEMENTS}\n`; + let outString = `# Excalidraw Data\n## Text Elements\n`; textElements.forEach(te=> { outString += `${te.rawText ?? (te.originalText ?? te.text)} ^${te.id}\n\n`; }); @@ -731,7 +729,7 @@ export class ExcalidrawAutomate { }) outString += Object.keys(this.imagesDict).length > 0 - ? "\n# Embedded files\n" + ? `\n## Embedded Files\n` : ""; Object.keys(this.imagesDict).forEach((key: FileId)=> { @@ -2776,9 +2774,9 @@ async function getTemplate( textMode, ); - let trimLocation = data.search(new RegExp(`^${MD_TEXTELEMENTS}$`,"m")); + let trimLocation = data.search(/^##? Text Elements$/m); if (trimLocation == -1) { - trimLocation = data.search(`${MD_DRAWING}\n`); + trimLocation = data.search(/##? Drawing\n/); } let scene = excalidrawData.scene; diff --git a/src/ExcalidrawData.ts b/src/ExcalidrawData.ts index a930aeb..e217b57 100644 --- a/src/ExcalidrawData.ts +++ b/src/ExcalidrawData.ts @@ -18,9 +18,6 @@ import { ERROR_IFRAME_CONVERSION_CANCELED, JSON_parse, FRONTMATTER_KEYS, - MD_TEXTELEMENTS, - MD_DRAWING, - MD_ELEMENTLINKS, } from "./constants/constants"; import { _measureText } from "./ExcalidrawAutomate"; import ExcalidrawPlugin from "./main"; @@ -117,12 +114,12 @@ export const REGEX_LINK = { }; //added \n at and of DRAWING_REG: https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/357 -const DRAWING_REG = /\n# Drawing\n[^`]*(```json\n)([\s\S]*?)```\n/gm; //https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/182 -const DRAWING_REG_FALLBACK = /\n# Drawing\n(```json\n)?(.*)(```)?(%%)?/gm; +const DRAWING_REG = /\n##? Drawing\n[^`]*(```json\n)([\s\S]*?)```\n/gm; //https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/182 +const DRAWING_REG_FALLBACK = /\n##? Drawing\n(```json\n)?(.*)(```)?(%%)?/gm; export const DRAWING_COMPRESSED_REG = - /(\n# Drawing\n[^`]*(?:```compressed\-json\n))([\s\S]*?)(```\n)/gm; //https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/182 + /(\n##? Drawing\n[^`]*(?:```compressed\-json\n))([\s\S]*?)(```\n)/gm; //https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/182 const DRAWING_COMPRESSED_REG_FALLBACK = - /(\n# Drawing\n(?:```compressed\-json\n)?)(.*)((```)?(%%)?)/gm; + /(\n##? Drawing\n(?:```compressed\-json\n)?)(.*)((```)?(%%)?)/gm; export const REG_LINKINDEX_HYPERLINK = /^\w+:\/\//; const isCompressedMD = (data: string): boolean => { @@ -204,10 +201,10 @@ export function getMarkdownDrawingSection( compressed: boolean, ) { return compressed - ? `# Drawing\n\x60\x60\x60compressed-json\n${compress( + ? `## Drawing\n\x60\x60\x60compressed-json\n${compress( jsonString, )}\n\x60\x60\x60\n%%` - : `# Drawing\n\x60\x60\x60json\n${jsonString}\n\x60\x60\x60\n%%`; + : `## Drawing\n\x60\x60\x60json\n${jsonString}\n\x60\x60\x60\n%%`; } /** @@ -241,33 +238,97 @@ const wrap = (text: string, lineLen: number) => lineLen ? wrapTextAtCharLength(text, lineLen, false, 0) : text; //WITHSECTION refers to back of the card note (see this.inputEl.onkeyup in SelectCard.ts) -const RE_TEXTELEMENTS_WITHSECTION_OK = new RegExp(`^#\n%%\n${MD_TEXTELEMENTS}(?:\n|$)`, "m"); -const RE_TEXTELEMENTS_WITHSECTION_NOTOK = new RegExp(`#\n%%\n${MD_TEXTELEMENTS}(?:\n|$)`, "m"); -const RE_TEXTELEMENTS_NOSECTION_OK = new RegExp(`^(%%\n)?${MD_TEXTELEMENTS}(?:\n|$)`, "m"); +const RE_EXCALIDRAWDATA_WITHSECTION_OK = new RegExp(`^#\n%%\n# Excalidraw Data(?:\n|$)`, "m"); +const RE_EXCALIDRAWDATA_WITHSECTION_NOTOK = new RegExp(`#\n%%\n# Excalidraw Data(?:\n|$)`, "m"); +const RE_EXCALIDRAWDATA_NOSECTION_OK = new RegExp(`^(%%\n)?# Excalidraw Data(?:\n|$)`, "m"); + +//WITHSECTION refers to back of the card note (see this.inputEl.onkeyup in SelectCard.ts) +const RE_TEXTELEMENTS_WITHSECTION_OK = new RegExp(`^#\n%%\n##? Text Elements(?:\n|$)`, "m"); +const RE_TEXTELEMENTS_WITHSECTION_NOTOK = new RegExp(`#\n%%\n##? Text Elements(?:\n|$)`, "m"); +const RE_TEXTELEMENTS_NOSECTION_OK = new RegExp(`^(%%\n)?##? Text Elements(?:\n|$)`, "m"); //The issue is that when editing in markdown embeds the user can delete the last enter causing two sections -//to collide. This is particularly problematic when the user is editing the lest section before # Text Elements -const RE_TEXTELEMENTS_FALLBACK_1 = new RegExp(`(.*)%%\n${MD_TEXTELEMENTS}(?:\n|$)`, "m"); -const RE_TEXTELEMENTS_FALLBACK_2 = new RegExp(`(.*)${MD_TEXTELEMENTS}(?:\n|$)`, "m"); +//to collide. This is particularly problematic when the user is editing the last section before # Text Elements +const RE_EXCALIDRAWDATA_FALLBACK_1 = new RegExp(`(.*)%%\n# Excalidraw Data(?:\n|$)`, "m"); +const RE_EXCALIDRAWDATA_FALLBACK_2 = new RegExp(`(.*)# Excalidraw Data(?:\n|$)`, "m"); + +const RE_TEXTELEMENTS_FALLBACK_1 = new RegExp(`(.*)%%\n##? Text Elements(?:\n|$)`, "m"); +const RE_TEXTELEMENTS_FALLBACK_2 = new RegExp(`(.*)##? Text Elements(?:\n|$)`, "m"); -const RE_DRAWING = new RegExp(`(%%\n)?${MD_DRAWING}\n`); +const RE_DRAWING = new RegExp(`(%%\n)?##? Drawing\n`); export const getExcalidrawMarkdownHeaderSection = (data:string, keys?:[string,string][]):string => { + //The base case scenario is at the top, continued with fallbacks in order of likelihood and file structure + //change history for sake of backward compatibility + /* Expected markdown structure: + bla bla bla + # + %% + # Excalidraw Data + */ + let trimLocation = data.search(RE_EXCALIDRAWDATA_WITHSECTION_OK); + let shouldFixTrailingHashtag = false; + if(trimLocation > 0) { + trimLocation += 2; //accounts for the "#\n" which I want to leave there untouched + } + + /* Expected markdown structure (this happens when the user deletes the last empty line of the last back-of-the-card note): + bla bla bla# + %% + # Excalidraw Data + */ + if(trimLocation === -1) { + trimLocation = data.search(RE_EXCALIDRAWDATA_WITHSECTION_NOTOK); + if(trimLocation > 0) { + shouldFixTrailingHashtag = true; + } + } + /* Expected markdown structure + a) + bla bla bla + %% + # Excalidraw Data + b) + bla bla bla + # Excalidraw Data + */ + if(trimLocation === -1) { + trimLocation = data.search(RE_EXCALIDRAWDATA_NOSECTION_OK); + } + /* Expected markdown structure: + bla bla bla%% + # Excalidraw Data + */ + if(trimLocation === -1) { + const res = data.match(RE_EXCALIDRAWDATA_FALLBACK_1); + if(res && Boolean(res[1])) { + trimLocation = res.index + res[1].length; + } + } + /* Expected markdown structure: + bla bla bla# Excalidraw Data + */ + if(trimLocation === -1) { + const res = data.match(RE_EXCALIDRAWDATA_FALLBACK_2); + if(res && Boolean(res[1])) { + trimLocation = res.index + res[1].length; + } + } /* Expected markdown structure: bla bla bla # %% # Text Elements */ - let trimLocation = data.search(RE_TEXTELEMENTS_WITHSECTION_OK); - let shouldFixTrailingHashtag = false; - if(trimLocation > 0) { - trimLocation += 2; + if(trimLocation === -1) { + trimLocation = data.search(RE_TEXTELEMENTS_WITHSECTION_OK); + if(trimLocation > 0) { + trimLocation += 2; //accounts for the "#\n" which I want to leave there untouched + } } - /* Expected markdown structure: bla bla bla# %% @@ -641,7 +702,28 @@ export class ExcalidrawData { //link was updated due to filename changes //The .excalidraw JSON is modified to reflect the MD in case of difference //Read the text elements into the textElements Map - let position = data.search(RE_TEXTELEMENTS_NOSECTION_OK); + let position = data.search(RE_EXCALIDRAWDATA_NOSECTION_OK); + if (position === -1) { + //resillience in case back of the note was saved right on top of text elements + // # back of note section + // ....# Excalidraw Data + // .... + // -------------- + // instead of + // -------------- + // # back of note section + // .... + // # Excalidraw Data + position = data.search(RE_EXCALIDRAWDATA_FALLBACK_2); + } + + if(position === -1) { + // # back of note section + // .... + // # Text Elements + position = data.search(RE_TEXTELEMENTS_NOSECTION_OK); + } + if (position === -1) { //resillience in case back of the note was saved right on top of text elements // # back of note section @@ -661,10 +743,12 @@ export class ExcalidrawData { return true; //Text Elements header does not exist } data = data.slice(position); - const normalMatch = data.match(new RegExp(`^((%%\n)?${MD_TEXTELEMENTS}(?:\n|$))`, "m")); + const normalMatch = data.match(/^((%%\n)?# Excalidraw Data\n## Text Elements(?:\n|$))/m) + ??data.match(/^((%%\n)?##? Text Elements(?:\n|$))/m); + const textElementsMatch = normalMatch ? normalMatch[0] - : data.match(new RegExp(`(.*${MD_TEXTELEMENTS}(?:\n|$))`, "m"))[0]; + : data.match(/(.*##? Text Elements(?:\n|$))/m)[0]; data = data.slice(textElementsMatch.length); this.textElementCommentedOut = textElementsMatch.startsWith("%%\n"); @@ -673,9 +757,13 @@ export class ExcalidrawData { //load element links const elementLinkMap = new Map(); - const elementLinksData = data.substring( - data.indexOf(`${MD_ELEMENTLINKS}\n`) + `${MD_ELEMENTLINKS}\n`.length, - ); + const indexOfNewElementLinks = data.indexOf("## Element Links\n"); + const lengthOfNewElementLinks = 17; //`## Element Links\n`.length + const indexOfOldElementLinks = data.indexOf("# Element Links\n"); + const lengthOfOldElementLinks = 16; //`# Element Links\n`.length + const elementLinksData = indexOfNewElementLinks>-1 + ? data.substring(indexOfNewElementLinks + lengthOfNewElementLinks) + : data.substring(indexOfOldElementLinks + lengthOfOldElementLinks); //Load Embedded files const RE_ELEMENT_LINKS = /^(.{8}):\s*(\[\[[^\]]*]])$/gm; const linksRes = elementLinksData.matchAll(RE_ELEMENT_LINKS); @@ -746,11 +834,15 @@ export class ExcalidrawData { } } - const indexOfEmbeddedFiles = data.indexOf("# Embedded files\n"); - if(indexOfEmbeddedFiles>-1) { - data = data.substring( - indexOfEmbeddedFiles + "# Embedded files\n".length, - ); + const indexOfNewEmbeddedFiles = data.indexOf("## Embedded Files\n"); + const embeddedFilesNewLength = 18; //"## Embedded Files\n".length + const indexOfOldEmbeddedFiles = data.indexOf("# Embedded files\n"); + const embeddedFilesOldLength = 17; //"# Embedded files\n".length + + if(indexOfNewEmbeddedFiles>-1 || indexOfOldEmbeddedFiles>-1) { + data = indexOfNewEmbeddedFiles>-1 + ? data.substring(indexOfNewEmbeddedFiles + embeddedFilesNewLength) + : data.substring(indexOfOldEmbeddedFiles + embeddedFilesOldLength); //Load Embedded files const REG_FILEID_FILEPATH = /([\w\d]*):\s*\[\[([^\]]*)]]\s?(\{[^}]*})?\n/gm; res = data.matchAll(REG_FILEID_FILEPATH); @@ -1265,7 +1357,7 @@ export class ExcalidrawData { disableCompression: boolean = false; generateMD(deletedElements: ExcalidrawElement[] = []): string { let outString = this.textElementCommentedOut ? "%%\n" : ""; - outString += `${MD_TEXTELEMENTS}\n`; + outString += `# Excalidraw Data\n## Text Elements\n`; const textElementLinks = new Map(); for (const key of this.textElements.keys()) { //https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/566 @@ -1281,7 +1373,7 @@ export class ExcalidrawData { } if (this.elementLinks.size > 0 || textElementLinks.size > 0) { - outString += `${MD_ELEMENTLINKS}\n`; + outString += `## Element Links\n`; for (const key of this.elementLinks.keys()) { outString += `${key}: ${this.elementLinks.get(key)}\n`; } @@ -1294,7 +1386,7 @@ export class ExcalidrawData { // deliberately not adding mermaids to here. It is enough to have the mermaidText in the image element's customData outString += this.equations.size > 0 || this.files.size > 0 - ? "# Embedded files\n" + ? "## Embedded Files\n" : ""; if (this.equations.size > 0) { for (const key of this.equations.keys()) { diff --git a/src/constants/constants.ts b/src/constants/constants.ts index 0555df7..b7547fd 100644 --- a/src/constants/constants.ts +++ b/src/constants/constants.ts @@ -9,13 +9,12 @@ export let EXCALIDRAW_PLUGIN: ExcalidrawPlugin = null; export const setExcalidrawPlugin = (plugin: ExcalidrawPlugin) => { EXCALIDRAW_PLUGIN = plugin; }; -export const MD_TEXTELEMENTS = "# Text Elements"; -export const MD_JSON_START = "```json\n"; -export const MD_JSON_END = "```"; -export const MD_DRAWING = "# Drawing"; -export const MD_ELEMENTLINKS = "# Element Links"; -export const MD_EMBEDFILES = "# Embedded files"; -export const MD_EX_SECTIONS = [MD_TEXTELEMENTS, MD_DRAWING, MD_ELEMENTLINKS, MD_EMBEDFILES]; +const MD_EXCALIDRAW = "# Excalidraw Data"; +const MD_TEXTELEMENTS = "## Text Elements"; +const MD_DRAWING = "## Drawing"; +const MD_ELEMENTLINKS = "## Element Links"; +const MD_EMBEDFILES = "## Embedded Files"; +export const MD_EX_SECTIONS = [MD_EXCALIDRAW, MD_TEXTELEMENTS, MD_DRAWING, MD_ELEMENTLINKS, MD_EMBEDFILES]; export const ERROR_IFRAME_CONVERSION_CANCELED = "iframe conversion canceled"; diff --git a/src/lang/locale/en.ts b/src/lang/locale/en.ts index 3893a66..f0a6cb7 100644 --- a/src/lang/locale/en.ts +++ b/src/lang/locale/en.ts @@ -9,6 +9,7 @@ export default { // main.ts CONVERT_URL_TO_FILE: "Save image from URL to local file", UNZIP_CURRENT_FILE: "Decompress current Excalidraw file", + ZIP_CURRENT_FILE: "Compress current Excalidraw file", PUBLISH_SVG_CHECK: "Obsidian Publish: Find SVG and PNG exports that are out of date", EMBEDDABLE_PROPERTIES: "Embeddable Properties", EMBEDDABLE_RELATIVE_ZOOM: "Scale selected embeddable elements to 100% relative to the current canvas zoom", diff --git a/src/main.ts b/src/main.ts index cb89cad..63451a2 100644 --- a/src/main.ts +++ b/src/main.ts @@ -20,7 +20,6 @@ import { Editor, MarkdownFileInfo, loadMermaid, - requireApiVersion, } from "obsidian"; import { BLANK_DRAWING, @@ -42,7 +41,6 @@ import { EXPORT_IMG_ICON, LOCALE, IMAGE_TYPES, - MD_TEXTELEMENTS, setExcalidrawPlugin, DEVICE } from "./constants/constants"; @@ -105,7 +103,7 @@ import { decompress, getImageSize, } from "./utils/Utils"; -import { editorInsertText, extractSVGPNGFileName, getActivePDFPageNumberFromPDFView, getAttachmentsFolderAndFilePath, getNewOrAdjacentLeaf, getParentOfClass, isObsidianThemeDark, mergeMarkdownFiles, openLeaf } from "./utils/ObsidianUtils"; +import { editorInsertText, extractSVGPNGFileName, foldExcalidrawSection, getActivePDFPageNumberFromPDFView, getAttachmentsFolderAndFilePath, getNewOrAdjacentLeaf, getParentOfClass, isObsidianThemeDark, mergeMarkdownFiles, openLeaf } from "./utils/ObsidianUtils"; import { ExcalidrawElement, ExcalidrawEmbeddableElement, ExcalidrawImageElement, ExcalidrawTextElement, FileId } from "@zsviczian/excalidraw/types/excalidraw/element/types"; import { ScriptEngine } from "./Scripts"; import { @@ -401,14 +399,14 @@ export default class ExcalidrawPlugin extends Plugin { debug(`ExcalidrawPlugin.switchToExcalidarwAfterLoad app.workspace.onLayoutReady`); let leaf: WorkspaceLeaf; for (leaf of this.app.workspace.getLeavesOfType("markdown")) { - if ( - leaf.view instanceof MarkdownView && - self.isExcalidrawFile(leaf.view.file) && - fileShouldDefaultAsExcalidraw(leaf.view.file?.path, self.app) - ) { - self.excalidrawFileModes[(leaf as any).id || leaf.view.file.path] = - VIEW_TYPE_EXCALIDRAW; - self.setExcalidrawView(leaf); + if ( leaf.view instanceof MarkdownView && self.isExcalidrawFile(leaf.view.file)) { + if (fileShouldDefaultAsExcalidraw(leaf.view.file?.path, self.app)) { + self.excalidrawFileModes[(leaf as any).id || leaf.view.file.path] = + VIEW_TYPE_EXCALIDRAW; + self.setExcalidrawView(leaf); + } else { + foldExcalidrawSection(leaf.view); + } } } }); @@ -878,7 +876,7 @@ export default class ExcalidrawPlugin extends Plugin { (async () => { const data = await this.app.vault.read(activeFile); - const parts = data.split("\n# Drawing\n```compressed-json\n"); + 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%%"); @@ -2281,12 +2279,13 @@ 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; + const maybeEAView = self.app?.workspace?.activeLeaf?.view; if(!maybeEAView || !(maybeEAView instanceof ExcalidrawView)) return result; const error = new Error(); const stackTrace = error.stack; @@ -2386,15 +2385,13 @@ export default class ExcalidrawPlugin extends Plugin { setViewState(next) { return function (state: ViewState, ...rest: any[]) { + const markdownViewLoaded = + self._loaded && // Don't force excalidraw mode during shutdown + state.type === "markdown" && // If we have a markdown file + state.state?.file; if ( - // Don't force excalidraw mode during shutdown - self._loaded && - // If we have a markdown file - state.type === "markdown" && - state.state?.file && - // And the current mode of the file is not set to markdown - self.excalidrawFileModes[this.id || state.state.file] !== - "markdown" + markdownViewLoaded && + self.excalidrawFileModes[this.id || state.state.file] !== "markdown" ) { if (fileShouldDefaultAsExcalidraw(state.state.file,this.app)) { // If we have it, force the view type to excalidraw @@ -2410,6 +2407,16 @@ export default class ExcalidrawPlugin extends Plugin { } } + if(markdownViewLoaded) { + const leaf = this; + setTimeout(async ()=> { + if(!leaf || !leaf.view || !(leaf.view instanceof MarkdownView) || + !leaf.view.file || !self.isExcalidrawFile(leaf.view.file) + ) return; + foldExcalidrawSection(leaf.view) + },500); + } + return next.apply(this, [state, ...rest]); }; }, @@ -3190,7 +3197,7 @@ export default class ExcalidrawPlugin extends Plugin { const textElements = excalidrawData.elements?.filter( (el: any) => el.type == "text", ); - let outString = `${MD_TEXTELEMENTS}\n`; + let outString = `# Excalidraw Data\n## Text Elements\n`; let id: string; for (const te of textElements) { id = te.id; @@ -3269,6 +3276,12 @@ export default class ExcalidrawPlugin extends Plugin { } as ViewState, eState ? eState : { focus: true }, ); + + const mdView = leaf.view; + if(mdView instanceof MarkdownView) { + foldExcalidrawSection(mdView); + } + } public async setExcalidrawView(leaf: WorkspaceLeaf) { diff --git a/src/types.d.ts b/src/types.d.ts index 91219ea..a9d7602 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -58,6 +58,20 @@ declare module "obsidian" { }, basePath: string; } + interface FoldPosition { + from: number; + to: number; + } + + interface FoldInfo { + folds: FoldPosition[]; + lines: number; + } + + interface MarkdownSubView { + applyFoldInfo(foldInfo: FoldInfo): void; + getFoldInfo(): FoldInfo | null; + } /*interface Editor { insertText(data: string): void; }*/ diff --git a/src/utils/ObsidianUtils.ts b/src/utils/ObsidianUtils.ts index aeb5035..001b809 100644 --- a/src/utils/ObsidianUtils.ts +++ b/src/utils/ObsidianUtils.ts @@ -2,13 +2,14 @@ import { App, Editor, FrontMatterCache, + MarkdownView, normalizePath, OpenViewState, parseFrontMatterEntry, TFile, View, Workspace, WorkspaceLeaf, WorkspaceSplit } from "obsidian"; import ExcalidrawPlugin from "../main"; import { checkAndCreateFolder, splitFolderAndFilename } from "./FileUtils"; import { linkClickModifierType, ModifierKeys } from "./ModifierkeyHelper"; import { REG_BLOCK_REF_CLEAN, REG_SECTION_REF_CLEAN } from "src/constants/constants"; -import yaml from "js-yaml"; +import yaml, { Mark } from "js-yaml"; export const getParentOfClass = (element: Element, cssClass: string):HTMLElement | null => { let parent = element.parentElement; @@ -350,4 +351,20 @@ export const editorInsertText = (editor: Editor, text: string)=> { const line = editor.getLine(cursor.line); const updatedLine = line.slice(0, cursor.ch) + text + line.slice(cursor.ch); editor.setLine(cursor.line, updatedLine); +} + +export const foldExcalidrawSection = (view: MarkdownView) => { + if(!view || !(view instanceof MarkdownView)) return; + const existingFolds = view.currentMode.getFoldInfo(); + const lineCount = view.editor.lineCount(); + let i = -1; + while(i++-1 && i