mirror of
https://github.com/zsviczian/obsidian-excalidraw-plugin.git
synced 2025-08-06 05:46:28 +00:00
1.6.21
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "obsidian-excalidraw-plugin",
|
||||
"name": "Excalidraw",
|
||||
"version": "1.6.20",
|
||||
"version": "1.6.21",
|
||||
"minAppVersion": "0.12.16",
|
||||
"description": "An Obsidian plugin to edit and view Excalidraw drawings",
|
||||
"author": "Zsolt Viczian",
|
||||
|
||||
@@ -727,7 +727,7 @@ export async function initExcalidrawAutomate(
|
||||
fontFamily: this.style.fontFamily,
|
||||
textAlign: formatting?.textAlign
|
||||
? formatting.textAlign
|
||||
: this.style.textAlign,
|
||||
: (this.style.textAlign ?? "left"),
|
||||
verticalAlign: this.style.verticalAlign,
|
||||
baseline,
|
||||
...boxedElement(id, "text", topX, topY, width, height),
|
||||
|
||||
@@ -406,7 +406,11 @@ export class ExcalidrawData {
|
||||
if (textEl) {
|
||||
if (textEl.type !== "text") {
|
||||
//markdown link attached to elements
|
||||
textEl.link = text;
|
||||
if(textEl.link!==text) {
|
||||
textEl.link = text;
|
||||
textEl.version++;
|
||||
textEl.versionNonce++;
|
||||
}
|
||||
this.elementLinks.set(id, text);
|
||||
} else {
|
||||
const wrapAt = estimateMaxLineLen(textEl.text, textEl.originalText);
|
||||
|
||||
@@ -40,6 +40,7 @@ import {
|
||||
REG_LINKINDEX_INVALIDCHARS,
|
||||
KEYCODE,
|
||||
LOCAL_PROTOCOL,
|
||||
REG_BLOCK_REF_CLEAN,
|
||||
} from "./Constants";
|
||||
import ExcalidrawPlugin from "./main";
|
||||
import { repositionElementsToCursor } from "./ExcalidrawAutomate";
|
||||
@@ -109,7 +110,8 @@ export const addFiles = async (
|
||||
if (!files || files.length === 0 || !view) {
|
||||
return;
|
||||
}
|
||||
files = files.filter((f) => f.size.height > 0 && f.size.width > 0); //height will be zero when file does not exisig in case of broken embedded file links
|
||||
//https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/544
|
||||
files = files.filter((f) => f && f.size && f.size.height > 0 && f.size.width > 0); //height will be zero when file does not exisig in case of broken embedded file links
|
||||
if (files.length === 0) {
|
||||
return;
|
||||
}
|
||||
@@ -145,6 +147,17 @@ export const addFiles = async (
|
||||
view.excalidrawAPI.addFiles(files);
|
||||
};
|
||||
|
||||
const warningUnknowSeriousError = () => {
|
||||
new Notice(
|
||||
"WARNING: Excalidraw ran into an unknown problem!!!\n\n" +
|
||||
"There is a risk that your most recent changes cannot be saved.\n\n" +
|
||||
"1) Please select your drawing using CTRL/CMD+A and make a copy with CTRL/CMD+C. " +
|
||||
"2) Then create an empty drawing in a new pane by CTRL/CMD+clicking the Excalidraw ribbon button, " +
|
||||
"3) and paste your work to the new document with CTRL/CMD+V.",
|
||||
60000,
|
||||
);
|
||||
}
|
||||
|
||||
export default class ExcalidrawView extends TextFileView {
|
||||
public excalidrawData: ExcalidrawData;
|
||||
public getScene: Function = null;
|
||||
@@ -190,7 +203,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
preventAutozoom: false,
|
||||
autosaving: false,
|
||||
dirty: null,
|
||||
preventReload: true,
|
||||
preventReload: false,
|
||||
isEditingText: false,
|
||||
saving: false,
|
||||
forceSaving: false,
|
||||
@@ -389,42 +402,51 @@ export default class ExcalidrawView extends TextFileView {
|
||||
return; //file was recently deleted
|
||||
}
|
||||
|
||||
//reload() is triggered indirectly when saving by the modifyEventHandler in main.ts
|
||||
//prevent reload is set here to override reload when not wanted: typically when the user is editing
|
||||
//and we do not want to interrupt the flow by reloading the drawing into the canvas.
|
||||
this.semaphores.preventReload = preventReload;
|
||||
const allowSave =
|
||||
(this.semaphores.dirty !== null && this.semaphores.dirty) ||
|
||||
this.semaphores.autosaving || forcesave; //dirty == false when view.file == null;
|
||||
const scene = this.getScene();
|
||||
try {
|
||||
const allowSave =
|
||||
(this.semaphores.dirty !== null && this.semaphores.dirty) ||
|
||||
this.semaphores.autosaving || forcesave; //dirty == false when view.file == null;
|
||||
const scene = this.getScene();
|
||||
|
||||
if (this.compatibilityMode) {
|
||||
await this.excalidrawData.syncElements(scene);
|
||||
} else if (
|
||||
(await this.excalidrawData.syncElements(scene)) &&
|
||||
!this.semaphores.autosaving
|
||||
) {
|
||||
await this.loadDrawing(false);
|
||||
}
|
||||
|
||||
if (allowSave) {
|
||||
await super.save();
|
||||
this.clearDirty();
|
||||
}
|
||||
|
||||
if (!this.semaphores.autosaving) {
|
||||
if (this.plugin.settings.autoexportSVG) {
|
||||
await this.saveSVG();
|
||||
}
|
||||
if (this.plugin.settings.autoexportPNG) {
|
||||
await this.savePNG();
|
||||
}
|
||||
if (
|
||||
!this.compatibilityMode &&
|
||||
this.plugin.settings.autoexportExcalidraw
|
||||
if (this.compatibilityMode) {
|
||||
await this.excalidrawData.syncElements(scene);
|
||||
} else if (
|
||||
(await this.excalidrawData.syncElements(scene)) &&
|
||||
!this.semaphores.autosaving
|
||||
) {
|
||||
this.saveExcalidraw();
|
||||
await this.loadDrawing(false);
|
||||
}
|
||||
|
||||
if (allowSave) {
|
||||
//reload() is triggered indirectly when saving by the modifyEventHandler in main.ts
|
||||
//prevent reload is set here to override reload when not wanted: typically when the user is editing
|
||||
//and we do not want to interrupt the flow by reloading the drawing into the canvas.
|
||||
this.semaphores.preventReload = preventReload;
|
||||
await super.save();
|
||||
this.clearDirty();
|
||||
}
|
||||
|
||||
if (!this.semaphores.autosaving) {
|
||||
if (this.plugin.settings.autoexportSVG) {
|
||||
await this.saveSVG();
|
||||
}
|
||||
if (this.plugin.settings.autoexportPNG) {
|
||||
await this.savePNG();
|
||||
}
|
||||
if (
|
||||
!this.compatibilityMode &&
|
||||
this.plugin.settings.autoexportExcalidraw
|
||||
) {
|
||||
this.saveExcalidraw();
|
||||
}
|
||||
}
|
||||
} catch(e) {
|
||||
errorlog({
|
||||
where:"ExcalidrawView.save",
|
||||
fn:this.save,
|
||||
error: e
|
||||
});
|
||||
warningUnknowSeriousError();
|
||||
}
|
||||
this.semaphores.saving = false;
|
||||
}
|
||||
@@ -866,19 +888,31 @@ export default class ExcalidrawView extends TextFileView {
|
||||
this.plugin.settings.autosave &&
|
||||
!this.semaphores.forceSaving
|
||||
) {
|
||||
this.autosaveTimer = null;
|
||||
this.semaphores.autosaving = true;
|
||||
if (this.excalidrawRef) {
|
||||
await this.save();
|
||||
}
|
||||
this.semaphores.autosaving = false;
|
||||
this.autosaveTimer = setTimeout(
|
||||
timer,
|
||||
this.plugin.settings.autosaveInterval,
|
||||
);
|
||||
} else {
|
||||
this.autosaveTimer = setTimeout(
|
||||
timer,
|
||||
this.isLoaded && this.plugin.activeExcalidrawView === this
|
||||
? 1000 //try again in 1 second
|
||||
: this.plugin.settings.autosaveInterval,
|
||||
);
|
||||
}
|
||||
};
|
||||
if (this.autosaveTimer) {
|
||||
clearInterval(this.autosaveTimer);
|
||||
clearTimeout(this.autosaveTimer);
|
||||
this.autosaveTimer = null;
|
||||
} // clear previous timer if one exists
|
||||
if (this.plugin.settings.autosave) {
|
||||
this.autosaveTimer = setInterval(
|
||||
this.autosaveTimer = setTimeout(
|
||||
timer,
|
||||
this.plugin.settings.autosaveInterval,
|
||||
);
|
||||
@@ -932,7 +966,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
}
|
||||
const loadOnModifyTrigger = file && file === this.file;
|
||||
if (loadOnModifyTrigger) {
|
||||
this.data = await this.app.vault.cachedRead(file);
|
||||
this.data = await this.app.vault.read(file);
|
||||
this.preventAutozoom();
|
||||
}
|
||||
if (fullreload) {
|
||||
@@ -1006,7 +1040,8 @@ export default class ExcalidrawView extends TextFileView {
|
||||
self.selectElementsMatchingQuery(
|
||||
elements,
|
||||
query,
|
||||
!this.excalidrawAPI.getAppState().viewModeEnabled
|
||||
!this.excalidrawAPI.getAppState().viewModeEnabled,
|
||||
true
|
||||
);
|
||||
},300);
|
||||
}
|
||||
@@ -1949,7 +1984,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
event: mouseEvent,
|
||||
source: VIEW_TYPE_EXCALIDRAW,
|
||||
hoverParent: hoverPreviewTarget,
|
||||
targetEl: hoverPreviewTarget,
|
||||
targetEl: null,//hoverPreviewTarget,
|
||||
linktext: this.plugin.hover.linkText,
|
||||
sourcePath: this.plugin.hover.sourcePath,
|
||||
});
|
||||
@@ -2581,15 +2616,26 @@ export default class ExcalidrawView extends TextFileView {
|
||||
this.plugin.saveSettings();
|
||||
}
|
||||
|
||||
public selectElementsMatchingQuery(elements:ExcalidrawElement[], query:string[], selectResult:boolean = true) {
|
||||
public selectElementsMatchingQuery(
|
||||
elements:ExcalidrawElement[],
|
||||
query:string[],
|
||||
selectResult:boolean = true,
|
||||
exactMatch: boolean = false //https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/530
|
||||
) {
|
||||
if(!elements || elements.length === 0 || !query || query.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const match = elements.filter((el: any) =>
|
||||
query.some((q) =>
|
||||
el.rawText.toLowerCase().replaceAll("\n", " ").match(q.toLowerCase()),
|
||||
),
|
||||
query.some((q) => {
|
||||
const text = el.rawText.toLowerCase().replaceAll("\n", " ").trim();
|
||||
if(exactMatch) {
|
||||
const m = text.match(/^#*(# .*)/);
|
||||
if(!m || m.length!==2) return false;
|
||||
return m[1] === q.toLowerCase();
|
||||
}
|
||||
return text.match(q.toLowerCase()); //to distinguish between "# frame" and "# frame 1"
|
||||
})
|
||||
);
|
||||
if (match.length === 0) {
|
||||
new Notice("I could not find a matching text element");
|
||||
@@ -2670,10 +2716,37 @@ export default class ExcalidrawView extends TextFileView {
|
||||
commitToHistory?: boolean,
|
||||
}, restore: boolean = false) {
|
||||
if(!this.excalidrawAPI) return;
|
||||
if(scene.elements && restore) {
|
||||
const shouldRestoreElements = scene.elements && restore;
|
||||
if(shouldRestoreElements) {
|
||||
scene.elements = this.excalidrawAPI.restore(scene).elements;
|
||||
}
|
||||
this.excalidrawAPI.updateScene(scene);
|
||||
try {
|
||||
this.excalidrawAPI.updateScene(scene);
|
||||
} catch(e) {
|
||||
errorlog({
|
||||
where:"ExcalidrawView.updateScene 1st attempt",
|
||||
fn:this.updateScene,
|
||||
error: e,
|
||||
scene: scene,
|
||||
willDoSecondAttempt: !shouldRestoreElements
|
||||
});
|
||||
if(!shouldRestoreElements) { //second attempt
|
||||
try {
|
||||
scene.elements = this.excalidrawAPI.restore(scene).elements;
|
||||
this.excalidrawAPI.updateScene(scene);
|
||||
} catch (e) {
|
||||
errorlog({
|
||||
where:"ExcalidrawView.updateScene 2nd attempt",
|
||||
fn:this.updateScene,
|
||||
error: e,
|
||||
scene: scene
|
||||
});
|
||||
warningUnknowSeriousError();
|
||||
}
|
||||
} else {
|
||||
warningUnknowSeriousError();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,13 @@ I develop this plugin as a hobby, spending most of my free time doing this. If y
|
||||
|
||||
<div class="ex-coffee-div"><a href="https://ko-fi.com/zsolt"><img src="https://cdn.ko-fi.com/cdn/kofi3.png?v=3" height=45></a></div>
|
||||
`,
|
||||
"1.6.21": `
|
||||
Before I move on to implementing further features, I spent this week with further stabilizing and debugging the plugin. Hopefully this will result in a smoother, better experince for you all.
|
||||
|
||||
## Fixed
|
||||
- Links in drawings (e.g. text elements or embedded images) were sometimes not updating when the source file was moved or renamed in your Vault. The issue happend when you had the drawing and the linked file open in panes next to each other. This has led to broken links. ([#546](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/546))
|
||||
- To remove complexity and potential error, I have hidden the autosave settings. From now, autosave is now always enabled. Excalidraw will attempt to save your drawing every 10 seconds, or if you are actively engaged in drawing a shape at that very moment (e.g. you are busy with a freedraw line), then autosave will save the drawing at the earliest next opportunity. I imlemented further triggers to save the drawing when there are changes in the drawing and you click outside the drawing canvas. There was a rare error involving text elements, that when happened blocked saving of the file. This error is now properly handeled. Also from now, you will receive a warning message if for any reason save encountered problems.
|
||||
- If you have two heading sections in your drawing, e.g. ${String.fromCharCode(96)}# Section abc${String.fromCharCode(96)} and ${String.fromCharCode(96)}# Section abc def${String.fromCharCode(96)}, then referencing ${String.fromCharCode(96)}[[#Section abc]]${String.fromCharCode(96)} in a link will highlight both text elements when clicking the link. These section references now work as expected. ([#530](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/530))`,
|
||||
"1.6.20": `
|
||||
<div class="excalidraw-videoWrapper"><div>
|
||||
<iframe src="https://www.youtube.com/embed/U2LkBRBk4LY" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
|
||||
93
src/main.ts
93
src/main.ts
@@ -119,7 +119,7 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
public insertLinkDialog: InsertLinkDialog;
|
||||
public insertImageDialog: InsertImageDialog;
|
||||
public insertMDDialog: InsertMDDialog;
|
||||
private activeExcalidrawView: ExcalidrawView = null;
|
||||
public activeExcalidrawView: ExcalidrawView = null;
|
||||
public lastActiveExcalidrawFilePath: string = null;
|
||||
public hover: { linkText: string; sourcePath: string } = {
|
||||
linkText: null,
|
||||
@@ -128,6 +128,9 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
private observer: MutationObserver;
|
||||
private themeObserver: MutationObserver;
|
||||
private fileExplorerObserver: MutationObserver;
|
||||
private modalContainerObserver: MutationObserver;
|
||||
private workspaceDrawerLeftObserver: MutationObserver;
|
||||
private workspaceDrawerRightObserver: MutationObserver;
|
||||
public opencount: number = 0;
|
||||
public ea: ExcalidrawAutomate;
|
||||
//A master list of fileIds to facilitate copy / paste
|
||||
@@ -1524,6 +1527,8 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
),
|
||||
);
|
||||
|
||||
self.addFileSaveTriggerEventHandlers();
|
||||
|
||||
const metaCache: MetadataCache = self.app.metadataCache;
|
||||
//@ts-ignore
|
||||
metaCache.getCachedFiles().forEach((filename: string) => {
|
||||
@@ -1546,6 +1551,83 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
});
|
||||
}
|
||||
|
||||
addFileSaveTriggerEventHandlers() {
|
||||
//https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/551
|
||||
const onClickEventSaveActiveDrawing = (e:PointerEvent) => {
|
||||
if(
|
||||
!this.activeExcalidrawView ||
|
||||
!this.activeExcalidrawView.semaphores.dirty ||
|
||||
//@ts-ignore
|
||||
e.target?.className === "excalidraw__canvas"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
this.activeExcalidrawView.save();
|
||||
}
|
||||
this.registerEvent(
|
||||
this.app.workspace.on("click",onClickEventSaveActiveDrawing)
|
||||
);
|
||||
|
||||
const onFileMenuEventSaveActiveDrawing = () => {
|
||||
if(
|
||||
!this.activeExcalidrawView ||
|
||||
!this.activeExcalidrawView.semaphores.dirty
|
||||
) {
|
||||
return;
|
||||
}
|
||||
this.activeExcalidrawView.save();
|
||||
}
|
||||
this.registerEvent(
|
||||
this.app.workspace.on("file-menu",onFileMenuEventSaveActiveDrawing)
|
||||
);
|
||||
|
||||
//The user clicks settings, or "open another vault", or the command palette
|
||||
this.modalContainerObserver = new MutationObserver(async (m: MutationRecord[]) => {
|
||||
if (
|
||||
m.length !== 1 ||
|
||||
m[0].type !== "childList" ||
|
||||
m[0].addedNodes.length !== 1 ||
|
||||
!this.activeExcalidrawView ||
|
||||
!this.activeExcalidrawView.semaphores.dirty
|
||||
) {
|
||||
return;
|
||||
}
|
||||
this.activeExcalidrawView.save();
|
||||
});
|
||||
this.modalContainerObserver.observe(document.body, {
|
||||
childList: true,
|
||||
});
|
||||
|
||||
//when the user activates the sliding drawers on Obsidian Mobile
|
||||
const leftWorkspaceDrawer = document.querySelector(".workspace-drawer.mod-left");
|
||||
const rightWorkspaceDrawer = document.querySelector(".workspace-drawer.mod-right");
|
||||
if(leftWorkspaceDrawer || rightWorkspaceDrawer) {
|
||||
const action = async (m: MutationRecord[]) => {
|
||||
if(m[0].oldValue !== "display: none;" ||
|
||||
!this.activeExcalidrawView ||
|
||||
!this.activeExcalidrawView.semaphores.dirty
|
||||
) {
|
||||
return;
|
||||
}
|
||||
this.activeExcalidrawView.save();
|
||||
};
|
||||
const options = {
|
||||
attributeOldValue: true,
|
||||
attributeFilter: ["style"],
|
||||
}
|
||||
|
||||
if(leftWorkspaceDrawer) {
|
||||
this.workspaceDrawerLeftObserver = new MutationObserver(action);
|
||||
this.workspaceDrawerLeftObserver.observe(leftWorkspaceDrawer, options);
|
||||
}
|
||||
|
||||
if(rightWorkspaceDrawer) {
|
||||
this.workspaceDrawerRightObserver = new MutationObserver(action);
|
||||
this.workspaceDrawerRightObserver.observe(rightWorkspaceDrawer, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateFileCache(
|
||||
file: TFile,
|
||||
frontmatter?: FrontMatterCache,
|
||||
@@ -1573,6 +1655,13 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
}
|
||||
this.observer.disconnect();
|
||||
this.themeObserver.disconnect();
|
||||
this.modalContainerObserver.disconnect();
|
||||
if(this.workspaceDrawerLeftObserver) {
|
||||
this.workspaceDrawerLeftObserver.disconnect();
|
||||
}
|
||||
if(this.workspaceDrawerRightObserver) {
|
||||
this.workspaceDrawerRightObserver.disconnect();
|
||||
}
|
||||
if (this.fileExplorerObserver) {
|
||||
this.fileExplorerObserver.disconnect();
|
||||
}
|
||||
@@ -1636,6 +1725,8 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
public async loadSettings() {
|
||||
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
|
||||
setLeftHandedMode(this.settings.isLeftHanded);
|
||||
this.settings.autosave = true;
|
||||
this.settings.autosaveInterval= 10000;
|
||||
}
|
||||
|
||||
async saveSettings() {
|
||||
|
||||
@@ -402,7 +402,7 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
|
||||
}),
|
||||
);
|
||||
|
||||
let autosaveDropdown: DropdownComponent;
|
||||
/* let autosaveDropdown: DropdownComponent;
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName(t("AUTOSAVE_NAME"))
|
||||
@@ -443,7 +443,7 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
|
||||
this.applySettingsUpdate(true);
|
||||
},
|
||||
);
|
||||
});
|
||||
});*/
|
||||
|
||||
this.containerEl.createEl("h1", { text: t("DISPLAY_HEAD") });
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"1.6.20": "0.12.16",
|
||||
"1.6.21": "0.12.16",
|
||||
"1.4.2": "0.11.13"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user