From 53c27f2a5952bdba8a170f2cb553e34e02354082 Mon Sep 17 00:00:00 2001 From: zsviczian Date: Sat, 13 Jul 2024 17:34:19 +0200 Subject: [PATCH] 2.2.9 --- manifest.json | 2 +- src/ExcalidrawView.ts | 229 +++++++++++++++++------------ src/dialogs/InsertCommandDialog.ts | 4 +- src/dialogs/InsertLinkDialog.ts | 4 +- src/dialogs/Messages.ts | 13 ++ src/dialogs/Prompt.ts | 12 +- src/main.ts | 104 ++++++------- src/menu/EmbeddableActionsMenu.tsx | 3 +- src/utils/ExcalidrawViewUtils.ts | 91 ++++++++++-- src/utils/StylesManager.ts | 13 +- 10 files changed, 295 insertions(+), 180 deletions(-) diff --git a/manifest.json b/manifest.json index 96a06a0..667ad80 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "obsidian-excalidraw-plugin", "name": "Excalidraw", - "version": "2.2.8", + "version": "2.2.9", "minAppVersion": "1.1.6", "description": "An Obsidian plugin to edit and view Excalidraw drawings", "author": "Zsolt Viczian", diff --git a/src/ExcalidrawView.ts b/src/ExcalidrawView.ts index 6ae3e7e..450f232 100644 --- a/src/ExcalidrawView.ts +++ b/src/ExcalidrawView.ts @@ -127,7 +127,7 @@ import { anyModifierKeysPressed, emulateKeysForLinkClick, webbrowserDragModifier import { setDynamicStyle } from "./utils/DynamicStyling"; import { InsertPDFModal } from "./dialogs/InsertPDFModal"; import { CustomEmbeddable, renderWebView } from "./customEmbeddable"; -import { addBackOfTheNoteCard, getExcalidrawFileForwardLinks, getFrameBasedOnFrameNameOrId, getLinkTextFromLink, insertEmbeddableToView, insertImageToView, openExternalLink, openTagSearch, renderContextMenuAction, tmpBruteForceCleanup } from "./utils/ExcalidrawViewUtils"; +import { addBackOfTheNoteCard, getExcalidrawFileForwardLinks, getFrameBasedOnFrameNameOrId, getLinkTextFromLink, insertEmbeddableToView, insertImageToView, openExternalLink, openTagSearch, parseObsidianLink, renderContextMenuAction, tmpBruteForceCleanup } from "./utils/ExcalidrawViewUtils"; import { imageCache } from "./utils/ImageCache"; import { CanvasNodeFactory, ObsidianCanvasNode } from "./utils/CanvasNodeFactory"; import { EmbeddableMenu } from "./menu/EmbeddableActionsMenu"; @@ -640,10 +640,9 @@ export default class ExcalidrawView extends TextFileView { } const reader = new FileReader(); reader.readAsDataURL(png); - const self = this; - reader.onloadend = function () { + reader.onloadend = () => { const base64data = reader.result; - download(null, base64data, `${self.file.basename}.png`); + download(null, base64data, `${this.file.basename}.png`); }; } @@ -683,12 +682,17 @@ export default class ExcalidrawView extends TextFileView { } async save(preventReload: boolean = true, forcesave: boolean = false, overrideEmbeddableIsEditingSelfDebounce: boolean = false) { - (process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.save, "ExcalidrawView.save, enter", preventReload, forcesave); + if ((process.env.NODE_ENV === 'development')) { + if (DEBUGGING) { + debug(this.save, "ExcalidrawView.save, enter", preventReload, forcesave); + console.trace(); + } + } /*if(this.semaphores.viewunload && (this.ownerWindow !== window)) { (process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.save, `ExcalidrawView.save, view is unloading, aborting save`); return; }*/ - + if(!this.isLoaded) { return; } @@ -759,6 +763,12 @@ export default class ExcalidrawView extends TextFileView { } await super.save(); + if (process.env.NODE_ENV === 'development') { + if (DEBUGGING) { + debug(this.save, `ExcalidrawView.save, super.save finished`, this.file); + console.trace(); + } + } //saving to backup with a delay in case application closes in the meantime, I want to avoid both save and backup corrupted. const path = this.file.path; //@ts-ignore @@ -1026,7 +1036,12 @@ export default class ExcalidrawView extends TextFileView { ? this.excalidrawData.getRawText(selectedText.id) : selectedText.text); - const partsArray = REGEX_LINK.getResList(linkText); + const maybeObsidianLink = parseObsidianLink(linkText, this.app); + if(typeof maybeObsidianLink === "string") { + linkText = maybeObsidianLink; + } + + const partsArray = REGEX_LINK.getResList(linkText); if (!linkText || partsArray.length === 0) { //the container link takes precedence over the text link if(selectedTextElement?.containerId) { @@ -1074,6 +1089,12 @@ export default class ExcalidrawView extends TextFileView { if(this.handleLinkHookCall(selectedElement,linkText,ev)) return; if(openExternalLink(linkText, this.app)) return; + const maybeObsidianLink = parseObsidianLink(linkText,this.app); + if (typeof maybeObsidianLink === "boolean" && maybeObsidianLink) return; + if (typeof maybeObsidianLink === "string") { + linkText = maybeObsidianLink; + } + const result = await linkPrompt(linkText, this.app, this); if(!result) return; [file, linkText, subpath] = result; @@ -1233,6 +1254,8 @@ export default class ExcalidrawView extends TextFileView { console.error(e); } + //if link will open in the same pane I want to save the drawing before opening the link + await this.forceSaveIfRequired(); const {leaf, promise} = openLeaf({ plugin: this.plugin, fnGetLeaf: () => getLeaf(this.plugin,this.leaf,keys), @@ -1470,20 +1493,21 @@ export default class ExcalidrawView extends TextFileView { this.offsetLeft = parent.offsetLeft; this.offsetTop = parent.offsetTop; - const self = this; + + //triggers when the leaf is moved in the workspace const observerFn = async (m: MutationRecord[]) => { - (process.env.NODE_ENV === 'development') && DEBUGGING && debug(observerFn, `ExcalidrawView.parentMoveObserver, file:${self.file?.name}`); + (process.env.NODE_ENV === 'development') && DEBUGGING && debug(observerFn, `ExcalidrawView.parentMoveObserver, file:${this.file?.name}`); const target = m[0].target; if (!(target instanceof HTMLElement)) { return; } const { offsetLeft, offsetTop } = target; - if (offsetLeft !== self.offsetLeft || offsetTop !== self.offsetTop) { - if (self.excalidrawAPI) { - self.refreshCanvasOffset(); + if (offsetLeft !== this.offsetLeft || offsetTop !== this.offsetTop) { + if (this.excalidrawAPI) { + this.refreshCanvasOffset(); } - self.offsetLeft = offsetLeft; - self.offsetTop = offsetTop; + this.offsetLeft = offsetLeft; + this.offsetTop = offsetTop; } }; this.parentMoveObserver = DEBUGGING @@ -1602,9 +1626,8 @@ export default class ExcalidrawView extends TextFileView { this.autosaveTimer = null; if (this.excalidrawAPI) { this.semaphores.autosaving = true; - const self = this; //changed from await to then to avoid lag during saving of large file - this.save().then(()=>self.semaphores.autosaving = false); + this.save().then(()=>this.semaphores.autosaving = false); } this.autosaveTimer = window.setTimeout( timer, @@ -1652,9 +1675,16 @@ export default class ExcalidrawView extends TextFileView { (process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.onUnloadFile,`ExcalidrawView.onUnloadFile, file:${this.file?.name}`); } - //onClose happens after onunload - protected async onClose(): Promise { - (process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.onClose,`ExcalidrawView.onClose, file:${this.file?.name}`); + private async forceSaveIfRequired():Promise { + (process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.forceSaveIfRequired,`ExcalidrawView.forceSaveIfRequired`); + let watchdog = 0; + let dirty = false; + //if saving was already in progress + //the function awaits the save to finish. + while (this.semaphores.saving && watchdog++ < 10) { + dirty = true; + await sleep(20); + } if(this.excalidrawAPI) { this.checkSceneVersion(this.excalidrawAPI.getSceneElements()); if(this.isDirty()) { @@ -1663,11 +1693,18 @@ export default class ExcalidrawView extends TextFileView { window.setTimeout(() => { plugin.triggerEmbedUpdates(path) },400); - + dirty = true; await this.save(true,true,true); } } + return dirty; + } + //onClose happens after onunload + protected async onClose(): Promise { + (process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.onClose,`ExcalidrawView.onClose, file:${this.file?.name}`); + + await this.forceSaveIfRequired(); if (this.excalidrawRoot) { this.excalidrawRoot.unmount(); this.excalidrawRoot = null; @@ -1858,7 +1895,7 @@ export default class ExcalidrawView extends TextFileView { if (!state) { return; } - const self = this; + let query: string[] = null; if ( @@ -1879,10 +1916,10 @@ export default class ExcalidrawView extends TextFileView { const waitForExcalidraw = async () => { let counter = 0; while ( - (self.semaphores.justLoaded || - !self.isLoaded || - !self.excalidrawAPI || - self.excalidrawAPI?.getAppState()?.isLoading) && + (this.semaphores.justLoaded || + !this.isLoaded || + !this.excalidrawAPI || + this.excalidrawAPI?.getAppState()?.isLoading) && counter++<100 ) await sleep(50); //https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/734 } @@ -1898,16 +1935,16 @@ export default class ExcalidrawView extends TextFileView { window.setTimeout(async () => { await waitForExcalidraw(); if(filenameParts.blockref && !filenameParts.hasGroupref) { - if(!self.getScene()?.elements.find((el:ExcalidrawElement)=>el.id === filenameParts.blockref)) { + if(!this.getScene()?.elements.find((el:ExcalidrawElement)=>el.id === filenameParts.blockref)) { const cleanQuery = cleanSectionHeading(filenameParts.blockref).replaceAll(" ",""); - const blocks = await self.getBackOfTheNoteBlocks(); + const blocks = await this.getBackOfTheNoteBlocks(); if(blocks.includes(cleanQuery)) { this.setMarkdownView(state); return; } } } - window.setTimeout(()=>self.zoomToElementId(filenameParts.blockref, filenameParts.hasGroupref)); + window.setTimeout(()=>this.zoomToElementId(filenameParts.blockref, filenameParts.hasGroupref)); }); } @@ -1921,7 +1958,7 @@ export default class ExcalidrawView extends TextFileView { window.setTimeout(async () => { await waitForExcalidraw(); - const api = self.excalidrawAPI; + const api = this.excalidrawAPI; if (!api) return; if (api.getAppState().isLoading) return; @@ -1933,17 +1970,17 @@ export default class ExcalidrawView extends TextFileView { if(parts) { const linkText = REGEX_LINK.getLink(parts); if(linkText) { - const file = self.plugin.app.metadataCache.getFirstLinkpathDest(linkText, self.file.path); + const file = this.plugin.app.metadataCache.getFirstLinkpathDest(linkText, this.file.path); if(file) { let fileId:FileId[] = []; - self.excalidrawData.files.forEach((ef,fileID) => { + this.excalidrawData.files.forEach((ef,fileID) => { if(ef.file?.path === file.path) fileId.push(fileID); }); if(fileId.length>0) { const images = elements.filter(el=>el.type === "image" && fileId.includes(el.fileId)); if(images.length>0) { this.preventAutozoom(); - window.setTimeout(()=>self.zoomToElements(!api.getAppState().viewModeEnabled, images)); + window.setTimeout(()=>this.zoomToElements(!api.getAppState().viewModeEnabled, images)); } } } @@ -1951,24 +1988,24 @@ export default class ExcalidrawView extends TextFileView { } } - if(!self.selectElementsMatchingQuery( + if(!this.selectElementsMatchingQuery( elements, query, !api.getAppState().viewModeEnabled, filenameParts.hasSectionref, filenameParts.hasGroupref )) { - const cleanQuery = cleanSectionHeading(query[0]).replaceAll(" ",""); - const sections = await self.getBackOfTheNoteSections(); + const cleanQuery = cleanSectionHeading(query[0]); + const sections = await this.getBackOfTheNoteSections(); if(sections.includes(cleanQuery)) { - self.setMarkdownView(state); + this.setMarkdownView(state); return; } } }); } - super.setEphemeralState(state); + //super.setEphemeralState(state); } // clear the view content @@ -2021,41 +2058,40 @@ export default class ExcalidrawView extends TextFileView { this.lastSaveTimestamp = this.file.stat.mtime; this.lastLoadedFile = this.file; data = this.data = data.replaceAll("\r\n", "\n").replaceAll("\r", "\n"); - const self = this; this.app.workspace.onLayoutReady(async () => { - (process.env.NODE_ENV === 'development') && DEBUGGING && debug(self.setViewData, `ExcalidrawView.setViewData > app.workspace.onLayoutReady, file:${self.file?.name}, isActiveLeaf:${self?.app?.workspace?.activeLeaf === self.leaf}`); + (process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.setViewData, `ExcalidrawView.setViewData > app.workspace.onLayoutReady, file:${this.file?.name}, isActiveLeaf:${this?.app?.workspace?.activeLeaf === this.leaf}`); //the leaf moved to a window and ExcalidrawView was destructed //Happens during Obsidian startup if View opens in new window. - if(!self?.app) { + if(!this?.app) { return; } let counter = 0; - while (!self.file && counter++<50) await sleep(50); - if(!self.file) return; - self.compatibilityMode = self.file.extension === "excalidraw"; - await self.plugin.loadSettings(); - if (self.compatibilityMode) { - self.plugin.enableLegacyFilePopoverObserver(); - self.actionButtons['isRaw'].hide(); - self.actionButtons['isParsed'].hide(); - self.actionButtons['link'].hide(); - self.textMode = TextMode.raw; - await self.excalidrawData.loadLegacyData(data, self.file); - if (!self.plugin.settings.compatibilityMode) { + while (!this.file && counter++<50) await sleep(50); + if(!this.file) return; + this.compatibilityMode = this.file.extension === "excalidraw"; + await this.plugin.loadSettings(); + if (this.compatibilityMode) { + this.plugin.enableLegacyFilePopoverObserver(); + this.actionButtons['isRaw'].hide(); + this.actionButtons['isParsed'].hide(); + this.actionButtons['link'].hide(); + this.textMode = TextMode.raw; + await this.excalidrawData.loadLegacyData(data, this.file); + if (!this.plugin.settings.compatibilityMode) { new Notice(t("COMPATIBILITY_MODE"), 4000); } - self.excalidrawData.disableCompression = true; + this.excalidrawData.disableCompression = true; } else { - self.actionButtons['link'].show(); - self.excalidrawData.disableCompression = false; + this.actionButtons['link'].show(); + this.excalidrawData.disableCompression = false; const textMode = getTextMode(data); - self.changeTextMode(textMode, false); + this.changeTextMode(textMode, false); try { if ( - !(await self.excalidrawData.loadData( + !(await this.excalidrawData.loadData( data, - self.file, - self.textMode, + this.file, + this.textMode, )) ) { return; @@ -2063,12 +2099,12 @@ export default class ExcalidrawView extends TextFileView { } catch (e) { errorlog({ where: "ExcalidrawView.setViewData", error: e }); if(e.message === ERROR_IFRAME_CONVERSION_CANCELED) { - self.setMarkdownView(); + this.setMarkdownView(); return; } - const file = self.file; - const plugin = self.plugin; - const leaf = self.leaf; + const file = this.file; + const plugin = this.plugin; + const leaf = this.leaf; (async () => { let confirmation:boolean = true; let counter = 0; @@ -2114,18 +2150,18 @@ export default class ExcalidrawView extends TextFileView { })(); - self.setMarkdownView(); + this.setMarkdownView(); return; } } - await self.loadDrawing(true); + await this.loadDrawing(true); - if(self.plugin.ea.onFileOpenHook) { + if(this.plugin.ea.onFileOpenHook) { const tempEA = getEA(this); try { - await self.plugin.ea.onFileOpenHook({ + await this.plugin.ea.onFileOpenHook({ ea: tempEA, - excalidrawFile: self.file, + excalidrawFile: this.file, view: this, }); } catch(e) { @@ -2135,20 +2171,19 @@ export default class ExcalidrawView extends TextFileView { } } - const script = self.excalidrawData.getOnLoadScript(); + const script = this.excalidrawData.getOnLoadScript(); if(script) { - const self = this; - const scriptname = self.file.basename+ "-onlaod-script"; + const scriptname = this.file.basename+ "-onlaod-script"; const runScript = () => { - if(!self.excalidrawAPI) { //need to wait for Excalidraw to initialize - window.setTimeout(runScript,200); + if(!this.excalidrawAPI) { //need to wait for Excalidraw to initialize + window.setTimeout(runScript.bind(this),200); return; } - self.plugin.scriptEngine.executeScript(self,script,scriptname,self.file); + this.plugin.scriptEngine.executeScript(this,script,scriptname,this.file); } runScript(); } - self.isLoaded = true; + this.isLoaded = true; }); } @@ -2188,11 +2223,10 @@ export default class ExcalidrawView extends TextFileView { //in case one or more files have not loaded retry later hoping that sync has delivered the file in the mean time. this.excalidrawData.getFiles().some(ef=>{ if(ef && !ef.file && ef.attemptCounter<30) { - const self = this; const currentFile = this.file.path; window.setTimeout(async ()=>{ - if(self && self.excalidrawAPI && currentFile === self.file.path) { - self.loadSceneFiles(); + if(this && this.excalidrawAPI && currentFile === this.file.path) { + this.loadSceneFiles(); } },2000) return true; @@ -2562,8 +2596,17 @@ export default class ExcalidrawView extends TextFileView { return ICON_NAME; } - setMarkdownView(eState?: any) { + async setMarkdownView(eState?: any) { (process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.setMarkdownView, "ExcalidrawView.setMarkdownView", eState); + //save before switching to markdown view. + //this would also happen onClose, but it does not hurt to save it here + //this way isDirty() will return false in onClose, thuse + //saving here will not result in double save + //there was a race condition when clicking a link with a section or block reference to the back-of-the-note + //that resulted in a call to save after the view has been destroyed + //The sleep is required for metadata cache to be updated with the location of the block or section + await this.forceSaveIfRequired(); + await sleep(200); //dirty hack to wait for Obsidian metadata to be updated, note that save may have been triggered elsewhere already this.plugin.excalidrawFileModes[this.id || this.file.path] = "markdown"; this.plugin.setMarkdownView(this.leaf, eState); } @@ -3393,8 +3436,7 @@ export default class ExcalidrawView extends TextFileView { } this.semaphores.hoverSleep = true; - const self = this; - window.setTimeout(() => (self.semaphores.hoverSleep = false), 500); + window.setTimeout(() => (this.semaphores.hoverSleep = false), 500); this.plugin.hover.linkText = linktext; this.plugin.hover.sourcePath = this.file.path; this.hoverPreviewTarget = this.contentEl; //e.target; @@ -3408,14 +3450,13 @@ export default class ExcalidrawView extends TextFileView { }); this.hoverPoint = this.currentPosition; if (this.isFullscreen()) { - const self = this; window.setTimeout(() => { const popover = this.ownerDocument.querySelector(`div.popover-title[data-path="${f.path}"]`) ?.parentElement?.parentElement?.parentElement ?? this.ownerDocument.body.querySelector("div.popover"); if (popover) { - self.contentEl.append(popover); + this.contentEl.append(popover); } }, 400); } @@ -3719,8 +3760,7 @@ export default class ExcalidrawView extends TextFileView { } } if (data.elements) { - const self = this; - window.setTimeout(() => self.save(), 300); //removed prevent reload = false, as reload was triggered when pasted containers were processed and there was a conflict with the new elements + window.setTimeout(() => this.save(), 30); //removed prevent reload = false, as reload was triggered when pasted containers were processed and there was a conflict with the new elements } return true; } @@ -4003,7 +4043,7 @@ export default class ExcalidrawView extends TextFileView { if(link.file.extension === "pdf") { const insertPDFModal = new InsertPDFModal(this.plugin, this); insertPDFModal.open(link.file); - return false; + //return false; } const ea = getEA(this) as ExcalidrawAutomate; insertImageToView(ea, pos, link.file).then(()=>ea.destroy()) ; @@ -4065,7 +4105,7 @@ export default class ExcalidrawView extends TextFileView { //return false; } } - if(localFileDragAction === "embeddable" || !IMAGE_TYPES.contains(extension)) { + else if(localFileDragAction === "embeddable" || !IMAGE_TYPES.contains(extension)) { const ea = getEA(this) as ExcalidrawAutomate; insertEmbeddableToView(ea, pos, null, link.url).then(()=>ea.destroy()); if(localFileDragAction !== "embeddable") { @@ -4216,7 +4256,7 @@ export default class ExcalidrawView extends TextFileView { (process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.onBeforeTextSubmit, "ExcalidrawView.onBeforeTextSubmit", textElement, nextText, nextOriginalText, isDeleted); const api = this.excalidrawAPI; if (!api) { - return {updatedNextOriginalText: null, nextLink: null}; + return {updatedNextOriginalText: null, nextLink: textElement?.link ?? null}; } // 1. Set the isEditingText flag to true to prevent autoresize on mobile @@ -4299,7 +4339,7 @@ export default class ExcalidrawView extends TextFileView { this.setDirty(9); } }); - return {updatedNextOriginalText: null, nextLink: null}; + return {updatedNextOriginalText: null, nextLink: textElement.link}; } else { new Notice(t("USE_INSERT_FILE_MODAL"),5000); } @@ -4372,12 +4412,12 @@ export default class ExcalidrawView extends TextFileView { //don't forget the case: link-prefix:"" && link-brackets:true return {updatedNextOriginalText: parseResultOriginal, nextLink: link}; } - return {updatedNextOriginalText: null, nextLink: null}; + return {updatedNextOriginalText: null, nextLink: textElement.link}; } //There were no links to parse, raw text and parsed text are equivalent api.history.clear(); return {updatedNextOriginalText: parseResultOriginal, nextLink:link}; } - return {updatedNextOriginalText: null, nextLink: null}; + return {updatedNextOriginalText: null, nextLink: textElement.link}; } // even if the text did not change, container sizes might need to be updated if (containerId) { @@ -4387,7 +4427,7 @@ export default class ExcalidrawView extends TextFileView { const parseResultOriginal = this.excalidrawData.getParsedText(textElement.id); return {updatedNextOriginalText: parseResultOriginal, nextLink: textElement.link}; } - return {updatedNextOriginalText: null, nextLink: null}; + return {updatedNextOriginalText: null, nextLink: textElement.link}; } private async onLinkOpen(element: ExcalidrawElement, e: any): Promise { @@ -4404,7 +4444,8 @@ export default class ExcalidrawView extends TextFileView { let event = e?.detail?.nativeEvent; if(this.handleLinkHookCall(element,element.link,event)) return; - if(openExternalLink(element.link, this.app, !isSHIFT(event) && !isWinCTRLorMacCMD(event) && !isWinMETAorMacCTRL(event) && !isWinALTorMacOPT(event) ? element : undefined)) return; + //if(openExternalLink(element.link, this.app, !isSHIFT(event) && !isWinCTRLorMacCMD(event) && !isWinMETAorMacCTRL(event) && !isWinALTorMacOPT(event) ? element : undefined)) return; + if(openExternalLink(element.link, this.app)) return; //if element is type text and element has multiple links, then submit the element text to linkClick to trigger link suggester if(element.type === "text") { @@ -4418,7 +4459,7 @@ export default class ExcalidrawView extends TextFileView { if (!event.shiftKey && !event.ctrlKey && !event.metaKey && !event.altKey) { event = emulateKeysForLinkClick("new-tab"); } - + this.linkClick( event, null, diff --git a/src/dialogs/InsertCommandDialog.ts b/src/dialogs/InsertCommandDialog.ts index e07ed63..5c1a4c3 100644 --- a/src/dialogs/InsertCommandDialog.ts +++ b/src/dialogs/InsertCommandDialog.ts @@ -46,7 +46,9 @@ export class InsertCommandDialog extends FuzzySuggestModal { } onClose(): void { - this.addText = null; + window.setTimeout(()=>{ + this.addText = null; + }) //onChooseItem must run first super.onClose(); } } diff --git a/src/dialogs/InsertLinkDialog.ts b/src/dialogs/InsertLinkDialog.ts index dec5f65..3f86eb3 100644 --- a/src/dialogs/InsertLinkDialog.ts +++ b/src/dialogs/InsertLinkDialog.ts @@ -58,7 +58,9 @@ export class InsertLinkDialog extends FuzzySuggestModal { } onClose(): void { - this.addText = null; + window.setTimeout(()=>{ + this.addText = null + }); //make sure this happens after onChooseItem runs super.onClose(); } diff --git a/src/dialogs/Messages.ts b/src/dialogs/Messages.ts index a419460..3f022d4 100644 --- a/src/dialogs/Messages.ts +++ b/src/dialogs/Messages.ts @@ -17,6 +17,19 @@ I develop this plugin as a hobby, spending my free time doing this. If you find
`, +"2.2.9": ` +## New +- Improved the "Open the back-of-the-note of the selected Excalidraw image" action. It now works with grouped elements and keeps the popout window within the visible screen area when elements are close to the top of the canvas. Note: Due to an Obsidian bug, I do not recommend using this feature with versions 1.6.0 - 1.6.6, if you have Obsidian Sync enabled, because Obsidian may freeze when closing the popout window. It functions properly in Obsidian versions before 1.6.0 and from 1.6.7 onwards. + +## Fixed +- Drag and drop from a local folder (outside Obsidian) resulted in duplicate images. +- Insert Link Action did not work [#1873](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/1873) +- Insert Obsidian Command Action did not work +- Element link for text element got deleted when editing the text. [#1878](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/1878) +- When back-of-the-drawing Section Headings have spaces in them, clicking the link opens the drawing side not the markdown side. [#1877](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/1877) +- obsidian:// links did not work as expected. [#1872](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/1872) +- copying and moving a rectangle with text, moves the text unexpectedly. The issue should now be resolved (at least much less likely to occur) [#1867](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/1867) +`, "2.2.8": ` While this release may appear modest with no new features, it represents nearly 50 hours of dedicated work. Here's what's been improved: diff --git a/src/dialogs/Prompt.ts b/src/dialogs/Prompt.ts index 797fc4e..396cfed 100644 --- a/src/dialogs/Prompt.ts +++ b/src/dialogs/Prompt.ts @@ -22,7 +22,7 @@ import { ExcalidrawAutomate } from "src/ExcalidrawAutomate"; import { MAX_IMAGE_SIZE, REG_LINKINDEX_INVALIDCHARS } from "src/constants/constants"; import { REGEX_LINK } from "src/ExcalidrawData"; import { ScriptEngine } from "src/Scripts"; -import { openExternalLink, openTagSearch } from "src/utils/ExcalidrawViewUtils"; +import { openExternalLink, openTagSearch, parseObsidianLink } from "src/utils/ExcalidrawViewUtils"; export type ButtonDefinition = { caption: string; tooltip?:string; action: Function }; @@ -708,7 +708,12 @@ export class ConfirmationPrompt extends Modal { } } -export const linkPrompt = async (linkText:string, app: App, view?: ExcalidrawView, message: string = "Select link to open"):Promise<[file:TFile, linkText:string, subpath: string]> => { +export async function linkPrompt ( + linkText:string, + app: App, + view?: ExcalidrawView, + message: string = "Select link to open", +):Promise<[file:TFile, linkText:string, subpath: string]> { const partsArray = REGEX_LINK.getResList(linkText); let subpath: string = null; let file: TFile = null; @@ -737,6 +742,9 @@ export const linkPrompt = async (linkText:string, app: App, view?: ExcalidrawVie linkText = REGEX_LINK.getLink(parts); if(openExternalLink(linkText, app)) return; + const maybeObsidianLink = parseObsidianLink(linkText, app, false); + if (typeof maybeObsidianLink === "boolean" && maybeObsidianLink) return; + if (typeof maybeObsidianLink === "string") linkText = maybeObsidianLink; if (linkText.search("#") > -1) { const linkParts = getLinkParts(linkText, view ? view.file : undefined); diff --git a/src/main.ts b/src/main.ts index bb9c9a2..63ad686 100644 --- a/src/main.ts +++ b/src/main.ts @@ -368,11 +368,10 @@ export default class ExcalidrawPlugin extends Plugin { this.switchToExcalidarwAfterLoad(); - const self = this; this.app.workspace.onLayoutReady(() => { - (process.env.NODE_ENV === 'development') && DEBUGGING && debug(self.onload,"ExcalidrawPlugin.onload > app.workspace.onLayoutReady"); - this.scriptEngine = new ScriptEngine(self); - imageCache.initializeDB(self); + (process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.onload,"ExcalidrawPlugin.onload > app.workspace.onLayoutReady"); + this.scriptEngine = new ScriptEngine(this); + imageCache.initializeDB(this); }); this.taskbone = new Taskbone(this); } @@ -380,9 +379,8 @@ export default class ExcalidrawPlugin extends Plugin { private setPropertyTypes() { if(!this.settings.loadPropertySuggestions) return; const app = this.app; - const self = this; this.app.workspace.onLayoutReady(() => { - (process.env.NODE_ENV === 'development') && DEBUGGING && debug(self.setPropertyTypes, `ExcalidrawPlugin.setPropertyTypes > app.workspace.onLayoutReady`); + (process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.setPropertyTypes, `ExcalidrawPlugin.setPropertyTypes > app.workspace.onLayoutReady`); Object.keys(FRONTMATTER_KEYS).forEach((key) => { if(FRONTMATTER_KEYS[key].depricated === true) return; const {name, type} = FRONTMATTER_KEYS[key]; @@ -392,9 +390,8 @@ export default class ExcalidrawPlugin extends Plugin { } public initializeFonts() { - const self = this; this.app.workspace.onLayoutReady(async () => { - (process.env.NODE_ENV === 'development') && DEBUGGING && debug(self.initializeFonts,`ExcalidrawPlugin.initializeFonts > app.workspace.onLayoutReady`); + (process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.initializeFonts,`ExcalidrawPlugin.initializeFonts > app.workspace.onLayoutReady`); const font = await getFontDataURL( this.app, this.settings.experimantalFourthFont, @@ -448,16 +445,15 @@ export default class ExcalidrawPlugin extends Plugin { } private switchToExcalidarwAfterLoad() { - const self = this; this.app.workspace.onLayoutReady(() => { - (process.env.NODE_ENV === 'development') && DEBUGGING && debug(self.switchToExcalidarwAfterLoad, `ExcalidrawPlugin.switchToExcalidarwAfterLoad > app.workspace.onLayoutReady`); + (process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.switchToExcalidarwAfterLoad, `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)) { - if (fileShouldDefaultAsExcalidraw(leaf.view.file?.path, self.app)) { - self.excalidrawFileModes[(leaf as any).id || leaf.view.file.path] = + if ( leaf.view instanceof MarkdownView && this.isExcalidrawFile(leaf.view.file)) { + if (fileShouldDefaultAsExcalidraw(leaf.view.file?.path, this.app)) { + this.excalidrawFileModes[(leaf as any).id || leaf.view.file.path] = VIEW_TYPE_EXCALIDRAW; - self.setExcalidrawView(leaf); + this.setExcalidrawView(leaf); } else { foldExcalidrawSection(leaf.view); } @@ -682,16 +678,15 @@ export default class ExcalidrawPlugin extends Plugin { initializeMarkdownPostProcessor(this); this.registerMarkdownPostProcessor(markdownPostProcessor); - const self = this; this.app.workspace.onLayoutReady(() => { - (process.env.NODE_ENV === 'development') && DEBUGGING && debug(self.addMarkdownPostProcessor, `ExcalidrawPlugin.addMarkdownPostProcessor > app.workspace.onLayoutReady`); + (process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.addMarkdownPostProcessor, `ExcalidrawPlugin.addMarkdownPostProcessor > app.workspace.onLayoutReady`); // internal-link quick preview - self.registerEvent(self.app.workspace.on("hover-link", hoverEvent)); + this.registerEvent(this.app.workspace.on("hover-link", hoverEvent)); //only add the legacy file observer if there are legacy files in the vault - if(self.app.vault.getFiles().some(f=>f.extension === "excalidraw")) { - self.enableLegacyFilePopoverObserver(); + if(this.app.vault.getFiles().some(f=>f.extension === "excalidraw")) { + this.enableLegacyFilePopoverObserver(); } }); } @@ -722,10 +717,9 @@ export default class ExcalidrawPlugin extends Plugin { const darkClass = bodyClassList.contains('theme-dark'); if (mutation?.oldValue?.includes('theme-dark') === darkClass) return; - const self = this; setTimeout(()=>{ //run async to avoid blocking the UI const theme = isObsidianThemeDark() ? "dark" : "light"; - const leaves = self.app.workspace.getLeavesOfType(VIEW_TYPE_EXCALIDRAW); + const leaves = this.app.workspace.getLeavesOfType(VIEW_TYPE_EXCALIDRAW); leaves.forEach((leaf: WorkspaceLeaf) => { const excalidrawView = leaf.view as ExcalidrawView; if (excalidrawView.file && excalidrawView.excalidrawAPI) { @@ -807,13 +801,12 @@ export default class ExcalidrawPlugin extends Plugin { ? new CustomMutationObserver(fileExplorerObserverFn, "fileExplorerObserver") : new MutationObserver(fileExplorerObserverFn); - const self = this; this.app.workspace.onLayoutReady(() => { - (process.env.NODE_ENV === 'development') && DEBUGGING && debug(self.experimentalFileTypeDisplay, `ExcalidrawPlugin.experimentalFileTypeDisplay > app.workspace.onLayoutReady`); + (process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.experimentalFileTypeDisplay, `ExcalidrawPlugin.experimentalFileTypeDisplay > app.workspace.onLayoutReady`); document.querySelectorAll(".nav-file-title").forEach(insertFiletype); //apply filetype to files already displayed const container = document.querySelector(".nav-files-container"); if (container) { - self.fileExplorerObserver.observe(container, { + this.fileExplorerObserver.observe(container, { childList: true, subtree: true, }); @@ -1650,26 +1643,31 @@ export default class ExcalidrawPlugin extends Plugin { 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"); + 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); - if(!ef) { - return false; - } - if(!this.isExcalidrawFile(ef.file)) { - return false; - } - if(checking) return true; this.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:centerX - width/2 + view.ownerWindow.screenX, - y:centerY - height/2 + view.ownerWindow.screenY, + x:Math.max(0,centerX - width/2 + view.ownerWindow.screenX), + y:Math.max(0,centerY - height/2 + view.ownerWindow.screenY), } this.openDrawing(ef.file, DEVICE.isMobile ? "new-tab":"popout-window", true, undefined, false, {x,y,width,height}); @@ -2555,21 +2553,20 @@ export default class ExcalidrawPlugin extends Plugin { if(!this.settings.startupScriptPath || this.settings.startupScriptPath === "") { return; } - const self = this; this.app.workspace.onLayoutReady(async () => { - (process.env.NODE_ENV === 'development') && DEBUGGING && debug(self.runStartupScript, `ExcalidrawPlugin.runStartupScript > app.workspace.onLayoutReady, scriptPath:${self.settings?.startupScriptPath}`); - const path = self.settings.startupScriptPath.endsWith(".md") - ? self.settings.startupScriptPath - : `${self.settings.startupScriptPath}.md`; - const f = self.app.vault.getAbstractFileByPath(path); + (process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.runStartupScript, `ExcalidrawPlugin.runStartupScript > app.workspace.onLayoutReady, scriptPath:${this.settings?.startupScriptPath}`); + const path = this.settings.startupScriptPath.endsWith(".md") + ? this.settings.startupScriptPath + : `${this.settings.startupScriptPath}.md`; + const f = this.app.vault.getAbstractFileByPath(path); if (!f || !(f instanceof TFile)) { new Notice(`Startup script not found: ${path}`); return; } - const script = await self.app.vault.read(f); + const script = await this.app.vault.read(f); const AsyncFunction = Object.getPrototypeOf(async () => {}).constructor; try { - await new AsyncFunction("ea", script)(self.ea); + await new AsyncFunction("ea", script)(this.ea); } catch (e) { new Notice(`Error running startup script: ${e}`); } @@ -2619,7 +2616,7 @@ export default class ExcalidrawPlugin extends Plugin { if (previouslyActiveEV.leaf !== leaf) { //if loading new view to same leaf then don't save. Excalidarw view will take care of saving anyway. //avoid double saving - if(previouslyActiveEV.semaphores?.dirty && !previouslyActiveEV.semaphores?.viewunload) { + if(previouslyActiveEV?.isDirty() && !previouslyActiveEV.semaphores?.viewunload) { await previouslyActiveEV.save(true); //this will update transclusions in the drawing } } @@ -2817,7 +2814,7 @@ export default class ExcalidrawPlugin extends Plugin { await inData.loadData(data,file,getTextMode(data)); excalidrawView.synchronizeWithData(inData); inData.destroy(); - if(excalidrawView.semaphores?.dirty) { + if(excalidrawView?.isDirty()) { if(excalidrawView.autosaveTimer && excalidrawView.autosaveFunction) { clearTimeout(excalidrawView.autosaveTimer); } @@ -2874,16 +2871,6 @@ export default class ExcalidrawPlugin extends Plugin { }; this.registerEvent(this.app.vault.on("delete", (file:TFile) => deleteEventHandler(file))); - //save open drawings when user quits the application - //Removing because it is not guaranteed to run, and frequently gets terminated mid flight, causing file consistency issues - /*const quitEventHandler = async () => { - const leaves = app.workspace.getLeavesOfType(VIEW_TYPE_EXCALIDRAW); - for (let i = 0; i < leaves.length; i++) { - await (leaves[i].view as ExcalidrawView).save(true); - } - }; - self.registerEvent(app.workspace.on("quit", quitEventHandler));*/ - //save Excalidraw leaf and update embeds when switching to another leaf this.registerEvent( this.app.workspace.on( @@ -2922,7 +2909,7 @@ export default class ExcalidrawPlugin extends Plugin { const onClickEventSaveActiveDrawing = (e: PointerEvent) => { if ( !this.activeExcalidrawView || - !this.activeExcalidrawView.semaphores?.dirty || + !this.activeExcalidrawView?.isDirty() || //@ts-ignore e.target && (e.target.className === "excalidraw__canvas" || //@ts-ignore @@ -2941,7 +2928,7 @@ export default class ExcalidrawPlugin extends Plugin { (process.env.NODE_ENV === 'development') && DEBUGGING && debug(onFileMenuEventSaveActiveDrawing,`ExcalidrawPlugin.onFileMenuEventSaveActiveDrawing`); if ( !this.activeExcalidrawView || - !this.activeExcalidrawView.semaphores?.dirty + !this.activeExcalidrawView?.isDirty() ) { return; } @@ -2965,7 +2952,7 @@ export default class ExcalidrawPlugin extends Plugin { if ( m[0].oldValue !== "display: none;" || !this.activeExcalidrawView || - !this.activeExcalidrawView.semaphores?.dirty + !this.activeExcalidrawView?.isDirty() ) { return; } @@ -3012,7 +2999,8 @@ export default class ExcalidrawPlugin extends Plugin { (m[0].type !== "childList") || (m[0].addedNodes.length !== 1) || (!this.activeExcalidrawView) || - (!this.activeExcalidrawView.semaphores?.dirty) + this.activeExcalidrawView?.semaphores?.viewunload || + (!this.activeExcalidrawView?.isDirty()) ) { return; } diff --git a/src/menu/EmbeddableActionsMenu.tsx b/src/menu/EmbeddableActionsMenu.tsx index 234ced3..8f19191 100644 --- a/src/menu/EmbeddableActionsMenu.tsx +++ b/src/menu/EmbeddableActionsMenu.tsx @@ -64,9 +64,8 @@ export class EmbeddableMenu { }; private handleMouseLeave () { - const self = this; this.menuFadeTimeout = window.setTimeout(() => { - self.containerRef.current?.style.setProperty("opacity", "0.2"); + this.containerRef.current?.style.setProperty("opacity", "0.2"); }, 5000); }; diff --git a/src/utils/ExcalidrawViewUtils.ts b/src/utils/ExcalidrawViewUtils.ts index 1fa0635..9e5ded5 100644 --- a/src/utils/ExcalidrawViewUtils.ts +++ b/src/utils/ExcalidrawViewUtils.ts @@ -12,12 +12,12 @@ import { ExcalidrawImperativeAPI } from "@zsviczian/excalidraw/types/excalidraw/ import { EmbeddableMDCustomProps } from "src/dialogs/EmbeddableSettings"; import { nanoid } from "nanoid"; -export const insertImageToView = async ( +export async function insertImageToView( ea: ExcalidrawAutomate, position: { x: number, y: number }, file: TFile | string, scale?: boolean, -):Promise => { +):Promise { ea.clear(); ea.style.strokeColor = "transparent"; ea.style.backgroundColor = "transparent"; @@ -33,12 +33,12 @@ export const insertImageToView = async ( return id; } -export const insertEmbeddableToView = async ( +export async function insertEmbeddableToView ( ea: ExcalidrawAutomate, position: { x: number, y: number }, file?: TFile, link?: string, -):Promise => { +):Promise { ea.clear(); ea.style.strokeColor = "transparent"; ea.style.backgroundColor = "transparent"; @@ -58,7 +58,7 @@ export const insertEmbeddableToView = async ( } } -export const getLinkTextFromLink = (text: string): string => { +export function getLinkTextFromLink (text: string): string { if (!text) return; if (text.match(REG_LINKINDEX_HYPERLINK)) return; @@ -71,7 +71,7 @@ export const getLinkTextFromLink = (text: string): string => { return linktext; } -export const openTagSearch = (link:string, app: App, view?: ExcalidrawView) => { +export function openTagSearch (link:string, app: App, view?: ExcalidrawView) { const tags = link .matchAll(/#([\p{Letter}\p{Emoji_Presentation}\p{Number}\/_-]+)/gu) .next(); @@ -92,21 +92,70 @@ export const openTagSearch = (link:string, app: App, view?: ExcalidrawView) => { return; } -export const openExternalLink = (link:string, app: App, element?: ExcalidrawElement):boolean => { +function getLinkFromMarkdownLink(link: string): string { + const result = /^\[[^\]]*]\(([^\)]*)\)/.exec(link); + return result ? result[1] : link; +} + +export function openExternalLink (link:string, app: App, element?: ExcalidrawElement):boolean { + link = getLinkFromMarkdownLink(link); if (link.match(/^cmd:\/\/.*/)) { const cmd = link.replace("cmd://", ""); //@ts-ignore app.commands.executeCommandById(cmd); return true; } - if (link.match(REG_LINKINDEX_HYPERLINK)) { - window.open(link, "_blank"); + if (!link.startsWith("obsidian://") && link.match(REG_LINKINDEX_HYPERLINK)) { + window.open(link, "_blank"); return true; } + return false; } -export const getExcalidrawFileForwardLinks = (app: App, excalidrawFile: TFile, secondOrderLinksSet: Set):string => { +/** + * + * @param link + * @param app + * @param returnWikiLink + * @returns + * false if the link is not an obsidian link, + * true if the link is an obsidian link and it was opened (i.e. it is a link to another Vault or not a file link e.g. plugin link), or + * the link to the file path. By default as a wiki link, or as a file path if returnWikiLink is false. + */ +export function parseObsidianLink(link: string, app: App, returnWikiLink: boolean = true): boolean | string { + link = getLinkFromMarkdownLink(link); + if (!link.startsWith("obsidian://")) { + return false; + } + const url = new URL(link); + const action = url.pathname.slice(2); // Remove leading '//' + + const props: {[key: string]: string} = {}; + url.searchParams.forEach((value, key) => { + props[key] = decodeURIComponent(value); + }); + + if (action === "open" && props.vault === app.vault.getName()) { + const file = props.file; + const f = app.metadataCache.getFirstLinkpathDest(file, ""); + if (f && f instanceof TFile) { + if (returnWikiLink) { + return `[[${f.path}]]`; + } else { + return f.path; + } + } + } + + window.open(link, "_blank"); + return true; +} + +export function getExcalidrawFileForwardLinks ( + app: App, excalidrawFile: TFile, + secondOrderLinksSet: Set, +):string { let secondOrderLinks = ""; const forwardLinks = app.metadataCache.getLinks()[excalidrawFile.path]; if(forwardLinks && forwardLinks.length > 0) { @@ -125,7 +174,10 @@ export const getExcalidrawFileForwardLinks = (app: App, excalidrawFile: TFile, s return secondOrderLinks; } -export const getFrameBasedOnFrameNameOrId = (frameName: string, elements: ExcalidrawElement[]): ExcalidrawFrameElement | null => { +export function getFrameBasedOnFrameNameOrId( + frameName: string, + elements: ExcalidrawElement[], +): ExcalidrawFrameElement | null { const frames = elements .filter((el: ExcalidrawElement)=>el.type==="frame") .map((el: ExcalidrawFrameElement, idx: number)=>{ @@ -136,7 +188,13 @@ export const getFrameBasedOnFrameNameOrId = (frameName: string, elements: Excali return frames.length === 1 ? frames[0] : null; } -export const addBackOfTheNoteCard = async (view: ExcalidrawView, title: string, activate: boolean = true, cardBody?: string, embeddableCustomData?: EmbeddableMDCustomProps):Promise => { +export async function addBackOfTheNoteCard( + view: ExcalidrawView, + title: string, + activate: boolean = true, + cardBody?: string, + embeddableCustomData?: EmbeddableMDCustomProps, +):Promise { const data = view.data; const header = getExcalidrawMarkdownHeaderSection(data); const body = data.split(header)[1]; @@ -186,7 +244,12 @@ export const addBackOfTheNoteCard = async (view: ExcalidrawView, title: string, return el.id; } -export const renderContextMenuAction = (React: any, label: string, action: Function, onClose: (callback?: () => void) => void) => { +export function renderContextMenuAction( + React: any, + label: string, + action: Function, + onClose: (callback?: () => void) => void, +) { return React.createElement ( "li", { @@ -218,7 +281,7 @@ export const renderContextMenuAction = (React: any, label: string, action: Funct ); } -export const tmpBruteForceCleanup = (view: ExcalidrawView) => { +export function tmpBruteForceCleanup (view: ExcalidrawView) { window.setTimeout(()=>{ if(!view) return; // const cleanupHTMLElement = (el: Element) => { diff --git a/src/utils/StylesManager.ts b/src/utils/StylesManager.ts index 419829d..557e347 100644 --- a/src/utils/StylesManager.ts +++ b/src/utils/StylesManager.ts @@ -37,23 +37,22 @@ export class StylesManager { constructor(plugin: ExcalidrawPlugin) { this.plugin = plugin; - const self = this; plugin.app.workspace.onLayoutReady(async () => { - (process.env.NODE_ENV === 'development') && DEBUGGING && debug(undefined, "StylesManager.constructor > app.workspace.onLayoutReady", self); - await self.harvestStyles(); - getAllWindowDocuments(plugin.app).forEach(doc => self.copyPropertiesToTheme(doc)); + (process.env.NODE_ENV === 'development') && DEBUGGING && debug(undefined, "StylesManager.constructor > app.workspace.onLayoutReady", this); + await this.harvestStyles(); + getAllWindowDocuments(plugin.app).forEach(doc => this.copyPropertiesToTheme(doc)); //initialize plugin.registerEvent( - plugin.app.workspace.on("css-change", ()=>self.onCSSChange()), + plugin.app.workspace.on("css-change", ()=>this.onCSSChange()), ) plugin.registerEvent( - plugin.app.workspace.on("window-open", (win)=>self.onWindowOpen(win)), + plugin.app.workspace.on("window-open", (win)=>this.onWindowOpen(win)), ) plugin.registerEvent( - plugin.app.workspace.on("window-close", (win)=>self.onWindowClose(win)), + plugin.app.workspace.on("window-close", (win)=>this.onWindowClose(win)), ) }); }