Skip to content

Commit b976a5d

Browse files
committed
2.15.3
1 parent 9221b8c commit b976a5d

11 files changed

Lines changed: 79 additions & 32 deletions

File tree

manifest-beta.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"id": "obsidian-excalidraw-plugin",
33
"name": "Excalidraw",
4-
"version": "2.15.3-beta-2",
4+
"version": "2.15.3",
55
"minAppVersion": "1.5.7",
66
"description": "An Obsidian plugin to edit and view Excalidraw drawings",
77
"author": "Zsolt Viczian",

manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"id": "obsidian-excalidraw-plugin",
33
"name": "Excalidraw",
4-
"version": "2.15.2",
4+
"version": "2.15.3",
55
"minAppVersion": "1.5.7",
66
"description": "An Obsidian plugin to edit and view Excalidraw drawings",
77
"author": "Zsolt Viczian",

src/core/main.ts

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ import { CommandManager } from "./managers/CommandManager";
9090
import { EventManager } from "./managers/EventManager";
9191
import { UniversalInsertFileModal } from "src/shared/Dialogs/UniversalInsertFileModal";
9292
import en from "src/lang/locale/en";
93-
import { VersionMismatchPrompt } from "src/shared/Dialogs/VersionMismatch";
9493

9594
declare const PLUGIN_VERSION:string;
9695
declare const INITIAL_TIMESTAMP: number;
@@ -424,21 +423,7 @@ export default class ExcalidrawPlugin extends Plugin {
424423
this.logStartupEvent("Switched to Excalidraw views");
425424

426425
try {
427-
let skipReleaseNotes = false;
428-
if (this.settings.compareManifestToPluginVersion) {
429-
if (this.manifest.version !== PLUGIN_VERSION) {
430-
const versionMismatchPrompt = new VersionMismatchPrompt(this);
431-
const result = await versionMismatchPrompt.start();
432-
if(result) {
433-
skipReleaseNotes = true;
434-
this.manifest.version = PLUGIN_VERSION;
435-
await this.app.setting.open();
436-
this.app.setting.openTabById("community-plugins");
437-
}
438-
}
439-
}
440-
441-
if (!skipReleaseNotes && this.settings.showReleaseNotes) {
426+
if (this.settings.showReleaseNotes) {
442427
//I am repurposing imageElementNotice, if the value is true, this means the plugin was just newly installed to Obsidian.
443428
const obsidianJustInstalled = (this.settings.previousRelease === "0.0.0") || !this.settings.previousRelease;
444429

src/lang/locale/en.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export default {
4444
TRANSCLUDE_MOST_RECENT: "Embed the most recently edited drawing",
4545
TOGGLE_LEFTHANDED_MODE: "Toggle left-handed mode",
4646
TOGGLE_SPLASHSCREEN: "Show splash screen in new drawings",
47-
FLIP_IMAGE: "Open the back-of-the-note for the selected image in a popout window",
47+
FLIP_IMAGE: "Open the back-of-the-note for the selected image in a popout window (flip the card)",
4848
NEW_IN_NEW_PANE: "Create new drawing - IN AN ADJACENT WINDOW",
4949
NEW_IN_NEW_TAB: "Create new drawing - IN A NEW TAB",
5050
NEW_IN_ACTIVE_PANE: "Create new drawing - IN THE CURRENT ACTIVE WINDOW",

src/shared/Dialogs/Messages.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,12 @@ I build this plugin in my free time, as a labor of love. Curious about the philo
2121
## Fixed
2222
- New back of the note cards are not visible until the drawing is saved. When adding a back-of-the-note card using the context menu, the card got placed at the absolute 0,0 position in the scene instead of the current pointer position. [#9949](https://github.com/excalidraw/excalidraw/issues/9949)
2323
- Drawings created 4 years ago don't open [#2479](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2479)
24+
- On Obsidian Mobile, when an element has multiple links, clicking the link icon, the link selector pops up and immediately closes
25+
- Improved handling of importing external images and drag and drop of images from inside Obsidian. Features like (Convert SVG to Strokes) and (Flip the card) now work immediately, you don't need to force save, or wait for autosave to kick in.
2426
2527
## New
2628
- Added startup check that detects when Obsidian's recorded plugin version differs from the installed Excalidraw code (e.g. after partial sync of large files) and offers to update or ignore, with a setting to disable the check.
29+
- When Excalidraw is open in two or more tabs—either as Markdown or Excalidraw—auto-zoom is disabled. This allows you to work in multiple tabs on the same drawing at once: focusing on different areas of the same drawing, or editing the Markdown and Excalidraw views in parallel.
2730
`,
2831
"2.15.2":`
2932
## Fixed:

src/shared/Dialogs/Prompt.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,6 +1011,7 @@ export async function linkPrompt(
10111011
...tagsArray,
10121012
];
10131013

1014+
await sleep(10); //obsidian modal link click immediately refocuses the editor, so we need to wait a bit
10141015
if (items.length>1) {
10151016
parts = await ScriptEngine.suggester(
10161017
app,

src/utils/excalidrawViewUtils.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@ export async function insertImageToView(
4040
return id;
4141
}
4242

43+
export function deleteAppStateKeys(
44+
st: AppState,
45+
[...keys]: (keyof AppState)[],
46+
): Partial<AppState> {
47+
keys.forEach((key) => {
48+
delete (st as Mutable<AppState>)[key];
49+
});
50+
return st;
51+
};
52+
4353
export async function insertEmbeddableToView (
4454
ea: ExcalidrawAutomate,
4555
position: { x: number, y: number },

src/utils/obsidianUtils.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {
33
Editor,
44
FrontMatterCache,
55
MarkdownView,
6-
OpenViewState, parseFrontMatterEntry, TFile, View, ViewState, Workspace, WorkspaceLeaf, WorkspaceSplit
6+
OpenViewState, parseFrontMatterEntry, TextFileView, TFile, View, ViewState, Workspace, WorkspaceLeaf, WorkspaceSplit
77
} from "obsidian";
88
import ExcalidrawPlugin from "../core/main";
99
import { splitFolderAndFilename } from "./fileUtils";
@@ -30,6 +30,14 @@ export function getExcalidrawViews(app: App): ExcalidrawView[] {
3030
return leaves.map(l=>l.view as ExcalidrawView);
3131
}
3232

33+
export function getExcalidraAndMarkdowViewsForFile(app: App, file: TFile): TextFileView[] {
34+
const leaves = [
35+
...app.workspace.getLeavesOfType(VIEW_TYPE_EXCALIDRAW).filter(l=>l.view instanceof ExcalidrawView),
36+
...app.workspace.getLeavesOfType("markdown").filter(l=>l.view instanceof MarkdownView)
37+
];
38+
return leaves.map(l=>l.view as TextFileView).filter(v=>v.file === file);
39+
}
40+
3341
export const getLeaf = (
3442
plugin: ExcalidrawPlugin,
3543
origo: WorkspaceLeaf,

src/utils/utils.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ import { runCompressionWorker } from "src/shared/Workers/compression-worker";
3333
import Pool from "es6-promise-pool";
3434
import { FileData } from "../shared/EmbeddedFileLoader";
3535
import { t } from "src/lang/helpers";
36-
import ExcalidrawScene from "src/shared/svgToExcalidraw/elements/ExcalidrawScene";
3736
import { log } from "./debugHelper";
37+
import { VersionMismatchPrompt } from "src/shared/Dialogs/VersionMismatch";
3838

3939
declare const PLUGIN_VERSION:string;
4040
declare var LZString: any;
@@ -51,6 +51,21 @@ declare module "obsidian" {
5151
}
5252
}
5353

54+
let versionMismatchChecked = false;
55+
export async function checkVersionMismatch(plugin: ExcalidrawPlugin) {
56+
if (!versionMismatchChecked && plugin.manifest.version !== PLUGIN_VERSION) {
57+
versionMismatchChecked = true;
58+
const versionMismatchPrompt = new VersionMismatchPrompt(plugin);
59+
const result = await versionMismatchPrompt.start();
60+
if(result) {
61+
plugin.manifest.version = PLUGIN_VERSION;
62+
await plugin.app.setting.open();
63+
plugin.app.setting.openTabById("community-plugins");
64+
}
65+
}
66+
};
67+
68+
5469
export let versionUpdateCheckTimer: number = null;
5570
let versionUpdateChecked = false;
5671
export async function checkExcalidrawVersion() {

src/view/ExcalidrawView.ts

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ import {
3838
DISK_ICON_NAME,
3939
SCRIPTENGINE_ICON_NAME,
4040
TEXT_DISPLAY_RAW_ICON_NAME,
41-
TEXT_DISPLAY_PARSED_ICON_NAME,
4241
IMAGE_TYPES,
4342
KEYCODE,
4443
FRONTMATTER_KEYS,
@@ -110,8 +109,9 @@ import {
110109
addAppendUpdateCustomData,
111110
getFilePathFromObsidianURL,
112111
getLinkParts,
112+
checkVersionMismatch,
113113
} from "../utils/utils";
114-
import { cleanBlockRef, cleanSectionHeading, closeLeafView, getActivePDFPageNumberFromPDFView, getAttachmentsFolderAndFilePath, getLeaf, getParentOfClass, obsidianPDFQuoteWithRef, openLeaf, setExcalidrawView } from "../utils/obsidianUtils";
114+
import { cleanBlockRef, cleanSectionHeading, closeLeafView, getAttachmentsFolderAndFilePath, getExcalidraAndMarkdowViewsForFile, getLeaf, getParentOfClass, obsidianPDFQuoteWithRef, openLeaf, setExcalidrawView } from "../utils/obsidianUtils";
115115
import { splitFolderAndFilename } from "../utils/fileUtils";
116116
import { GenericInputPrompt, MultiOptionConfirmationPrompt, NewFileActions, Prompt, linkPrompt } from "../shared/Dialogs/Prompt";
117117
import { ClipboardData } from "@zsviczian/excalidraw/types/excalidraw/clipboard";
@@ -130,10 +130,10 @@ import { getTextElementAtPointer, getImageElementAtPointer, getElementWithLinkAt
130130
import { excalidrawSword, ICONS, LogoWrapper, Rank, saveIcon, SwordColors } from "../constants/actionIcons";
131131
import { ExportDialog } from "../shared/Dialogs/ExportDialog";
132132
import { getEA } from "src/core"
133-
import { anyModifierKeysPressed, emulateKeysForLinkClick, isWinALTorMacOPT, isWinCTRLorMacCMD, isWinMETAorMacCTRL, isSHIFT, linkClickModifierType, localFileDragModifierType, ModifierKeys, modifierKeyTooltipMessages } from "../utils/modifierkeyHelper";
133+
import { anyModifierKeysPressed, emulateKeysForLinkClick, isWinALTorMacOPT, isWinCTRLorMacCMD, isWinMETAorMacCTRL, isSHIFT, linkClickModifierType, ModifierKeys } from "../utils/modifierkeyHelper";
134134
import { setDynamicStyle } from "../utils/dynamicStyling";
135135
import { CustomEmbeddable, renderWebView } from "./components/CustomEmbeddable";
136-
import { addBackOfTheNoteCard, getExcalidrawFileForwardLinks, getFrameBasedOnFrameNameOrId, getLinkTextFromLink, insertEmbeddableToView, insertImageToView, isTextImageTransclusion, onLoadMessages, openExternalLink, parseObsidianLink, renderContextMenuAction, tmpBruteForceCleanup, toggleImageAnchoring } from "../utils/excalidrawViewUtils";
136+
import { addBackOfTheNoteCard, deleteAppStateKeys, getExcalidrawFileForwardLinks, getFrameBasedOnFrameNameOrId, getLinkTextFromLink, insertEmbeddableToView, insertImageToView, isTextImageTransclusion, onLoadMessages, openExternalLink, parseObsidianLink, renderContextMenuAction, tmpBruteForceCleanup, toggleImageAnchoring } from "../utils/excalidrawViewUtils";
137137
import { imageCache } from "../shared/ImageCache";
138138
import { CanvasNodeFactory, ObsidianCanvasNode } from "./managers/CanvasNodeFactory";
139139
import { EmbeddableMenu } from "./components/menu/EmbeddableActionsMenu";
@@ -2165,7 +2165,7 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
21652165
await this.excalidrawData.setTextMode(this.textMode);
21662166
}
21672167
this.excalidrawData.scene.appState.theme = api.getAppState().theme;
2168-
await this.loadDrawing(loadOnModifyTrigger);
2168+
await this.loadDrawing(loadOnModifyTrigger, undefined, true);
21692169
this.clearDirty();
21702170
}
21712171

@@ -2356,6 +2356,7 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
23562356
if(this.lastLoadedFile === this.file) return;
23572357
this.isLoaded = false;
23582358
if(!this.file) return;
2359+
if(this.plugin.settings.compareManifestToPluginVersion) checkVersionMismatch(this.plugin);
23592360
if(this.plugin.settings.showNewVersionNotification) checkExcalidrawVersion();
23602361
if(isMaskFile(this.plugin,this.file)) {
23612362
const notice = new Notice(t("MASK_FILE_NOTICE"), 5000);
@@ -2778,9 +2779,10 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
27782779
*
27792780
* @param justloaded - a flag to trigger zoom to fit after the drawing has been loaded
27802781
*/
2781-
public async loadDrawing(justloaded: boolean, deletedElements?: ExcalidrawElement[]) {
2782+
public async loadDrawing(justloaded: boolean, deletedElements?: ExcalidrawElement[], isReloading: boolean = false) {
27822783
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.loadDrawing, "ExcalidrawView.loadDrawing", justloaded, deletedElements);
27832784
const excalidrawData = this.excalidrawData.scene;
2785+
const isOpenInMultipleLeaves = getExcalidraAndMarkdowViewsForFile(this.app,this.file).length > 1;
27842786
this.semaphores.justLoaded = justloaded;
27852787
this.clearDirty();
27862788
const om = this.excalidrawData.getOpenMode();
@@ -2798,7 +2800,6 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
27982800
//debug({where:"ExcalidrawView.loadDrawing",file:this.file.name,dataTheme:excalidrawData.appState.theme,before:"updateScene"})
27992801
//api.setLocalFont(this.plugin.settings.experimentalEnableFourthFont);
28002802

2801-
28022803
this.updateScene(
28032804
{
28042805
elements: excalidrawData.elements.concat(deletedElements??[]), //need to preserve deleted elements during autosave if images, links, etc. are updated
@@ -2811,7 +2812,9 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
28112812
{
28122813
//elements: excalidrawData.elements.concat(deletedElements??[]), //need to preserve deleted elements during autosave if images, links, etc. are updated
28132814
appState: {
2814-
...excalidrawData.appState,
2815+
...isReloading && isOpenInMultipleLeaves
2816+
? deleteAppStateKeys(excalidrawData.appState, ["scrollX","scrollY","zoom"])
2817+
: excalidrawData.appState,
28152818
...this.excalidrawData.selectedElementIds //https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/609
28162819
? this.excalidrawData.selectedElementIds
28172820
: {},
@@ -2846,7 +2849,9 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
28462849
this.instantiateExcalidraw({
28472850
elements: excalidrawData.elements,
28482851
appState: {
2849-
...excalidrawData.appState,
2852+
...isReloading && isOpenInMultipleLeaves
2853+
? deleteAppStateKeys(excalidrawData.appState, ["scrollX","scrollY","zoom"])
2854+
: excalidrawData.appState,
28502855
...excalidrawData.appState.frameRendering && excalidrawData.appState.frameRendering.markerName === undefined
28512856
? { frameRendering: {...excalidrawData.appState.frameRendering, markerName: true, markerEnabled: true } }
28522857
: {},
@@ -4047,7 +4052,23 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
40474052
}
40484053
}
40494054

4055+
private shouldSaveImportedImage: boolean = false;
40504056
private onChange (et: ExcalidrawElement[], st: AppState) {
4057+
if(st.activeTool?.type) {
4058+
if(st.activeTool.type === "image") {
4059+
if(st.selectedElementIds && Object.keys(st.selectedElementIds).length === 1) {
4060+
const selectedElement = et.filter(el=>el.id === Object.keys(st.selectedElementIds)[0])[0];
4061+
if(selectedElement && selectedElement.type === "image") {
4062+
this.shouldSaveImportedImage = true;
4063+
}
4064+
}
4065+
}
4066+
if(st.activeTool.type === "selection" && this.shouldSaveImportedImage) {
4067+
this.shouldSaveImportedImage = false;
4068+
setTimeout(()=>this.save(true, true),100); //image is being added to the scene
4069+
}
4070+
}
4071+
40514072
if(st.newElement?.type === "freedraw") {
40524073
this.freedrawLastActiveTimestamp = Date.now();
40534074
}
@@ -4064,7 +4085,9 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
40644085
if( elcount>0 && et.length===0 ) return;
40654086
this.semaphores.justLoaded = false;
40664087
if (!this.semaphores.preventAutozoom && this.plugin.settings.zoomToFitOnOpen) {
4067-
this.zoomToFit(false,true);
4088+
if(getExcalidraAndMarkdowViewsForFile(this.app, this.file).length === 1) {
4089+
this.zoomToFit(false,true);
4090+
}
40684091
}
40694092
this.previousSceneVersion = this.getSceneVersion(et);
40704093
this.previousBackgroundColor = st.viewBackgroundColor;
@@ -4237,7 +4260,8 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
42374260
}
42384261
}
42394262
if (data.elements) {
4240-
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
4263+
const preventReload = !(data.elements.some((el) => el.type === "image") && !data.elements.some((el) => el.type !== "image"));
4264+
window.setTimeout(() => this.save(preventReload), 30); //removed prevent reload = false, as reload was triggered when pasted containers were processed and there was a conflict with the new elements
42414265
}
42424266

42434267
//process pasted text after it was processed into elements by Excalidraw

0 commit comments

Comments
 (0)