Compare commits

...

25 Commits

Author SHA1 Message Date
zsviczian
8adcb7d850 pdfjs rendering race condition 2024-12-20 20:08:55 +01:00
zsviczian
be383f2b48 moved Drop handlers to DropManager, added await to page.getViewport as there seems to be a race condition impacting page.render() 2024-12-20 19:32:37 +01:00
zsviczian
682307b51d Merge pull request #2169 from zsviczian/2.7.2-casing
2.7.2 file and folder name casing + empty line before ## Text Elements
2024-12-20 14:14:14 +01:00
zsviczian
60328613ea empty line before ## Text Elements 2024-12-20 13:12:36 +00:00
zsviczian
4a2e054ac6 cleaned up filename and folder letter-cases 2024-12-20 12:59:17 +00:00
zsviczian
eebc428f1b major file reorganization 2024-12-19 22:29:51 +01:00
zsviczian
ab8ba66eb5 Merge pull request #2166 from dmscode/master
Update zh-cn.ts to 6733f76
2024-12-19 15:09:09 +01:00
dmscode
97b3050270 Update zh-cn.ts to 6733f76
Please don't use auto formater in language file, now, in zh-cn.ts, every items have the same line-number with en.ts, for easy to find and change.
2024-12-19 09:44:26 +08:00
zsviczian
6733f76fbf 2.7.1 2024-12-18 21:59:46 +01:00
zsviczian
1dcc45585d Merge pull request #2165 from zsviczian/2.7.1-beta-1
fixed unescape, decodeURIComponent issue with non-latin characters.
2024-12-18 17:58:45 +01:00
zsviczian
0c5ceaa3f7 fixed unescape, decodeURIComponent issue with non-latin characters.
exitFullscreen when closing the view.
2024-12-18 10:22:27 +00:00
zsviczian
2e602d49a2 Merge pull request #2163 from hackerESQ/master
Allow poorly formated .excalidraw files to render
2024-12-18 10:10:08 +01:00
hackerESQ
84bcdf8bee Merge pull request #1 from hackerESQ/enable-poorly-formatted-json-legacy-mode
Allow poorly formated .excalidraw files to render
2024-12-17 22:07:26 -06:00
hackerESQ
6d60bcf6eb Allow poorly formated .excalidraw files to render
There are several excalidraw implementations which fail to follow the defined excalidraw JSON schema. This allows those poorly formatted files to render in legacy mode in Obsidian.
2024-12-17 22:06:54 -06:00
zsviczian
b832a51a5b Merge pull request #2160 from zsviczian/2.7.0-bugs
Fix ROOTELEMENTSIZE calc, view switch timestamp logic, update global app refs, minify packages, fix FileManager init, add 2.7.0 notes
2024-12-17 18:01:02 +01:00
zsviczian
dd4c07cbf9 ROOTELEMENTSIZE calculation based on overrideObsidianFontSize 2024-12-17 16:51:12 +00:00
zsviczian
6a86de3e1e splitViewLeafSwitchTimestamp should only be set if switching from markdown to Excalidraw view 2024-12-17 16:31:39 +00:00
zsviczian
ff8c649c6a isRecentSplitViewSwitch 2024-12-17 16:03:55 +00:00
zsviczian
ae34e124a7 updated remaining instances of reference to global app 2024-12-17 12:40:10 +00:00
zsviczian
5d084ffc30 minify react and excalidraw, fix filemanager instantiation, added 2.7.0 release notes 2024-12-17 10:34:59 +00:00
zsviczian
b0a9cf848e 2.7.0-beta-7 (0.17.6-22) Modified rollup to load packages in new Function instead of window.eval 2024-12-16 20:56:47 +01:00
zsviczian
37e06efa43 fixed packageLoader for popout windows, getSharedMermaidInstance (load mermaid) 2024-12-16 18:53:39 +01:00
zsviczian
3a6ad7d762 2.7.0-beta-6 (language compress) 2024-12-15 19:26:10 +01:00
zsviczian
2846b358f4 EventManager and improved type safety (removed //@ts-ignore 2024-12-15 15:28:10 +01:00
zsviczian
8b3c22cc7f Carved out CommandManager from main.ts 2024-12-15 07:48:38 +01:00
115 changed files with 17412 additions and 17234 deletions

View File

@@ -15,9 +15,15 @@ let html: any;
let preamble: string;
function svgToBase64(svg: string): string {
return `data:image/svg+xml;base64,${btoa(
decodeURIComponent(encodeURIComponent(svg.replaceAll(" ", " "))),
)}`;
const cleanSvg = svg.replaceAll(" ", " ");
// Convert the string to UTF-8 and handle non-Latin1 characters
const encodedData = encodeURIComponent(cleanSvg)
.replace(/%([0-9A-F]{2})/g,
(match, p1) => String.fromCharCode(parseInt(p1, 16))
);
return `data:image/svg+xml;base64,${btoa(encodedData)}`;
}
async function getImageSize(src: string): Promise<{ height: number; width: number }> {

View File

@@ -1,16 +1,16 @@
/// <reference types="react" />
import ExcalidrawPlugin from "src/main";
import ExcalidrawPlugin from "src/core/main";
import { FillStyle, StrokeStyle, ExcalidrawElement, ExcalidrawBindableElement, FileId, NonDeletedExcalidrawElement, ExcalidrawImageElement, StrokeRoundness, RoundnessType } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { Editor, OpenViewState, TFile, WorkspaceLeaf } from "obsidian";
import * as obsidian_module from "obsidian";
import ExcalidrawView, { ExportSettings } from "src/ExcalidrawView";
import ExcalidrawView, { ExportSettings } from "src/view/ExcalidrawView";
import { AppState, BinaryFileData, DataURL, ExcalidrawImperativeAPI, Point } from "@zsviczian/excalidraw/types/excalidraw/types";
import { EmbeddedFilesLoader } from "src/EmbeddedFileLoader";
import { ConnectionPoint, DeviceType } from "src/types/types";
import { ColorMaster } from "colormaster";
import { TInput } from "colormaster/types";
import { ClipboardData } from "@zsviczian/excalidraw/types/excalidraw/clipboard";
import { PaneTarget } from "src/utils/ModifierkeyHelper";
import { PaneTarget } from "src/utils/modifierkeyHelper";
export declare class ExcalidrawAutomate {
/**
* Utility function that returns the Obsidian Module object.

View File

@@ -17,7 +17,7 @@ import { ConnectionPoint, DeviceType } from "src/types";
import { ColorMaster } from "colormaster";
import { TInput } from "colormaster/types";
import { ClipboardData } from "@zsviczian/excalidraw/types/clipboard";
import { PaneTarget } from "src/utils/ModifierkeyHelper";
import { PaneTarget } from "src/utils/modifierkeyHelper";
export declare class ExcalidrawAutomate {
/**
* Utility function that returns the Obsidian Module object.

View File

@@ -1,7 +1,7 @@
{
"id": "obsidian-excalidraw-plugin",
"name": "Excalidraw",
"version": "2.7.0-beta-5",
"version": "2.7.1",
"minAppVersion": "1.1.6",
"description": "An Obsidian plugin to edit and view Excalidraw drawings",
"author": "Zsolt Viczian",

View File

@@ -1,7 +1,7 @@
{
"id": "obsidian-excalidraw-plugin",
"name": "Excalidraw",
"version": "2.6.8",
"version": "2.7.1",
"minAppVersion": "1.1.6",
"description": "An Obsidian plugin to edit and view Excalidraw drawings",
"author": "Zsolt Viczian",

View File

@@ -16,14 +16,15 @@
"build:mathjax": "cd MathjaxToSVG && npm run build",
"build:all": "npm run build:mathjax && npm run build",
"dev:mathjax": "cd MathjaxToSVG && npm run dev",
"dev:all": "npm run dev:mathjax && npm run dev"
"dev:all": "npm run dev:mathjax && npm run dev",
"build:lang": "node ./scripts/compressLanguages.js"
},
"keywords": [],
"author": "",
"license": "MIT",
"dependencies": {
"@popperjs/core": "^2.11.8",
"@zsviczian/excalidraw": "0.17.6-21",
"@zsviczian/excalidraw": "0.17.6-22",
"chroma-js": "^2.4.2",
"clsx": "^2.0.0",
"@zsviczian/colormaster": "^1.2.2",
@@ -72,7 +73,7 @@
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.0",
"lz-string": "^1.5.0",
"obsidian": "1.5.7-1",
"obsidian": "^1.7.2",
"prettier": "^3.0.1",
"rollup": "^2.70.1",
"rollup-plugin-copy": "^3.5.0",
@@ -81,7 +82,9 @@
"rollup-plugin-typescript2": "^0.34.1",
"tslib": "^2.6.1",
"ttypescript": "^1.5.15",
"typescript": "^5.2.2"
"typescript": "^5.2.2",
"fs-extra": "^11.2.0",
"uglify-js": "^3.19.3"
},
"resolutions": {
"@typescript-eslint/typescript-estree": "5.3.0"

View File

@@ -5,31 +5,68 @@ import { terser } from "rollup-plugin-terser";
import copy from "rollup-plugin-copy";
import typescript2 from "rollup-plugin-typescript2";
import fs from 'fs';
import path from 'path';
import LZString from 'lz-string';
import postprocess from '@zsviczian/rollup-plugin-postprocess';
import cssnano from 'cssnano';
import jsesc from 'jsesc';
import { minify } from 'uglify-js';
// Load environment variables
import dotenv from 'dotenv';
dotenv.config();
const DIST_FOLDER = 'dist';
const absolutePath = path.resolve(DIST_FOLDER);
fs.mkdirSync(absolutePath, { recursive: true });
const isProd = (process.env.NODE_ENV === "production");
const isLib = (process.env.NODE_ENV === "lib");
console.log(`Running: ${process.env.NODE_ENV}; isProd: ${isProd}; isLib: ${isLib}`);
const mathjaxtosvg_pkg = isLib ? "" : fs.readFileSync("./MathjaxToSVG/dist/index.js", "utf8");
const excalidraw_pkg = isLib ? "" : isProd
const LANGUAGES = ['ru', 'zh-cn']; //english is not compressed as it is always loaded by default
function trimLastSemicolon(input) {
if (input.endsWith(";")) {
return input.slice(0, -1);
}
return input;
}
function minifyCode(code) {
const minified = minify(code,{
compress: true,
mangle: true,
output: {
comments: false,
beautify: false,
},
});
if (minified.error) {
throw new Error(minified.error);
}
return minified.code;
}
function compressLanguageFile(lang) {
const inputDir = "./src/lang/locale";
const filePath = `${inputDir}/${lang}.ts`;
let content = fs.readFileSync(filePath, "utf-8");
content = trimLastSemicolon(content.split("export default")[1].trim());
return LZString.compressToBase64(minifyCode(`x = ${content};`));
}
const excalidraw_pkg = isLib ? "" : minifyCode( isProd
? fs.readFileSync("./node_modules/@zsviczian/excalidraw/dist/excalidraw.production.min.js", "utf8")
: fs.readFileSync("./node_modules/@zsviczian/excalidraw/dist/excalidraw.development.js", "utf8");
const react_pkg = isLib ? "" : isProd
: fs.readFileSync("./node_modules/@zsviczian/excalidraw/dist/excalidraw.development.js", "utf8"));
const react_pkg = isLib ? "" : minifyCode(isProd
? fs.readFileSync("./node_modules/react/umd/react.production.min.js", "utf8")
: fs.readFileSync("./node_modules/react/umd/react.development.js", "utf8");
const reactdom_pkg = isLib ? "" : isProd
: fs.readFileSync("./node_modules/react/umd/react.development.js", "utf8"));
const reactdom_pkg = isLib ? "" : minifyCode(isProd
? fs.readFileSync("./node_modules/react-dom/umd/react-dom.production.min.js", "utf8")
: fs.readFileSync("./node_modules/react-dom/umd/react-dom.development.js", "utf8");
: fs.readFileSync("./node_modules/react-dom/umd/react-dom.development.js", "utf8"));
const lzstring_pkg = isLib ? "" : fs.readFileSync("./node_modules/lz-string/libs/lz-string.min.js", "utf8");
if (!isLib) {
@@ -60,19 +97,15 @@ const packageString = isLib
'\nlet REACT_PACKAGES = `' +
jsesc(react_pkg + reactdom_pkg, { quotes: 'backtick' }) +
'`;\n' +
/* 'let EXCALIDRAW_PACKAGE = `' +
jsesc(excalidraw_pkg, { quotes: 'backtick' }) +
'`;\n' +*/
'const unpackExcalidraw = () => LZString.decompressFromBase64("' + LZString.compressToBase64(excalidraw_pkg) + '");\n' +
'let {react, reactDOM } = window.eval.call(window, `(function() {' + '${REACT_PACKAGES};' + 'return {react: React, reactDOM: ReactDOM};})();`);\n' +
'let {react, reactDOM } = new Function(`${REACT_PACKAGES}; return {react: React, reactDOM: ReactDOM};`)();\n' +
'let excalidrawLib = {};\n' +
'const loadMathjaxToSVG = () => window.eval.call(window, `(function() {' +
'${LZString.decompressFromBase64("' + LZString.compressToBase64(mathjaxtosvg_pkg) + '")}' +
'return MathjaxToSVG;})();`);\n' +
'const loadMathjaxToSVG = () => new Function(`${LZString.decompressFromBase64("' + LZString.compressToBase64(mathjaxtosvg_pkg) + '")}; return MathjaxToSVG;`)();\n' +
`const PLUGIN_LANGUAGES = {${LANGUAGES.map(lang => `"${lang}": "${compressLanguageFile(lang)}"`).join(",")}};\n` +
'const PLUGIN_VERSION="' + manifest.version + '";';
const BASE_CONFIG = {
input: 'src/main.ts',
input: 'src/core/main.ts',
external: [
'@codemirror/autocomplete',
'@codemirror/collab',
@@ -111,7 +144,12 @@ const BUILD_CONFIG = {
exports: 'default',
},
plugins: getRollupPlugins(
{tsconfig: isProd ? "tsconfig.json" : "tsconfig.dev.json"},
{
tsconfig: isProd ? "tsconfig.json" : "tsconfig.dev.json",
sourcemap: !isProd,
clean: true,
//verbosity: isProd ? 1 : 2,
},
...(isProd ? [
terser({
toplevel: false,
@@ -136,10 +174,10 @@ const BUILD_CONFIG = {
const LIB_CONFIG = {
...BASE_CONFIG,
input: "src/index.ts",
input: "src/core/index.ts",
output: {
dir: "lib",
sourcemap: true,
sourcemap: false,
format: "cjs",
name: "Excalidraw (Library)",
},

View File

@@ -1,368 +0,0 @@
import ExcalidrawPlugin from "./main";
export class OneOffs {
private plugin: ExcalidrawPlugin;
constructor(plugin: ExcalidrawPlugin) {
this.plugin = plugin;
}
/*
public patchCommentBlock() {
//This is a once off cleanup process to remediate incorrectly placed comment %% before # Text Elements
if (!this.plugin.settings.patchCommentBlock) {
return;
}
const plugin = this.plugin;
log(
`${window
.moment()
.format("HH:mm:ss")}: Excalidraw will patch drawings in 5 minutes`,
);
setTimeout(async () => {
await plugin.loadSettings();
if (!plugin.settings.patchCommentBlock) {
log(
`${window
.moment()
.format(
"HH:mm:ss",
)}: Excalidraw patching aborted because synched data.json is already patched`,
);
return;
}
log(
`${window
.moment()
.format("HH:mm:ss")}: Excalidraw is starting the patching process`,
);
let i = 0;
const excalidrawFiles = plugin.app.vault.getFiles();
for (const f of (excalidrawFiles || []).filter((f: TFile) =>
plugin.isExcalidrawFile(f),
)) {
if (
f.extension !== "excalidraw" && //legacy files do not need to be touched
plugin.app.workspace.getActiveFile() !== f
) {
//file is currently being edited
let drawing = await plugin.app.vault.read(f);
const orig_drawing = drawing;
drawing = drawing.replaceAll("\r\n", "\n").replaceAll("\r", "\n"); //Win, Mac, Linux compatibility
drawing = drawing.replace(
"\n%%\n# Text Elements\n",
"\n# Text Elements\n",
);
if (drawing.search("\n%%\n# Drawing\n") === -1) {
const sceneJSONandPOS = getJSON(drawing);
drawing = `${drawing.substr(
0,
sceneJSONandPOS.pos,
)}\n%%\n# Drawing\n\`\`\`json\n${sceneJSONandPOS.scene}\n\`\`\`%%`;
}
if (drawing !== orig_drawing) {
i++;
log(`Excalidraw patched: ${f.path}`);
await plugin.app.vault.modify(f, drawing);
}
}
}
plugin.settings.patchCommentBlock = false;
plugin.saveSettings();
log(
`${window
.moment()
.format("HH:mm:ss")}: Excalidraw patched in total ${i} files`,
);
}, 300000); //5 minutes
}
public migrationNotice() {
if (this.plugin.settings.loadCount > 0) {
return;
}
const plugin = this.plugin;
plugin.app.workspace.onLayoutReady(async () => {
plugin.settings.loadCount++;
plugin.saveSettings();
const files = plugin.app.vault
.getFiles()
.filter((f) => f.extension === "excalidraw");
if (files.length > 0) {
const prompt = new MigrationPrompt(plugin.app, plugin);
prompt.open();
}
});
}
public imageElementLaunchNotice() {
if (!this.plugin.settings.imageElementNotice) {
return;
}
const plugin = this.plugin;
plugin.app.workspace.onLayoutReady(async () => {
const prompt = new ImageElementNotice(plugin.app, plugin);
prompt.open();
});
}
public wysiwygPatch() {
if (this.plugin.settings.patchCommentBlock) {
return;
} //the comment block patch needs to happen first (unlikely that someone has waited this long with the update...)
//This is a once off process to patch excalidraw files remediate incorrectly placed comment %% before # Text Elements
if (
!(
this.plugin.settings.runWYSIWYGpatch ||
this.plugin.settings.fixInfinitePreviewLoop
)
) {
return;
}
const plugin = this.plugin;
log(
`${window
.moment()
.format(
"HH:mm:ss",
)}: Excalidraw will patch drawings to support WYSIWYG in 7 minutes`,
);
setTimeout(async () => {
await plugin.loadSettings();
if (
!(
this.plugin.settings.runWYSIWYGpatch ||
this.plugin.settings.fixInfinitePreviewLoop
)
) {
log(
`${window
.moment()
.format(
"HH:mm:ss",
)}: Excalidraw patching aborted because synched data.json is already patched`,
);
return;
}
log(
`${window
.moment()
.format("HH:mm:ss")}: Excalidraw is starting the patching process`,
);
let i = 0;
const excalidrawFiles = plugin.app.vault.getFiles();
for (const f of (excalidrawFiles || []).filter((f: TFile) =>
plugin.isExcalidrawFile(f),
)) {
if (
f.extension !== "excalidraw" && //legacy files do not need to be touched
plugin.app.workspace.getActiveFile() !== f
) {
//file is currently being edited
try {
const excalidrawData = new ExcalidrawData(plugin);
const data = await plugin.app.vault.read(f);
const textMode = getTextMode(data);
await excalidrawData.loadData(data, f, textMode);
let trimLocation = data.search(/(^%%\n)?# Text Elements\n/m);
if (trimLocation == -1) {
trimLocation = data.search(/(%%\n)?# Drawing\n/);
}
if (trimLocation > -1) {
let header = data
.substring(0, trimLocation)
.replace(
/excalidraw-plugin:\s.*\n/,
`${FRONTMATTER_KEY}: ${
textMode == TextMode.raw ? "raw\n" : "parsed\n"
}`,
);
header = header.replace(
/cssclass:[\s]*excalidraw-hide-preview-text[\s]*\n/,
"",
);
const REG_IMG = /(^---[\w\W]*?---\n)(!\[\[.*?]]\n(%%\n)?)/m; //(%%\n)? because of 1.4.8-beta... to be backward compatible with anyone who installed that version
if (header.match(REG_IMG)) {
header = header.replace(REG_IMG, "$1");
}
const newData = header + excalidrawData.generateMD();
if (data !== newData) {
i++;
log(`Excalidraw patched: ${f.path}`);
await plugin.app.vault.modify(f, newData);
}
}
} catch (e) {
errorlog({
where: "OneOffs.wysiwygPatch",
message: `Unable to process: ${f.path}`,
error: e,
});
}
}
}
plugin.settings.runWYSIWYGpatch = false;
plugin.settings.fixInfinitePreviewLoop = false;
plugin.saveSettings();
log(
`${window
.moment()
.format("HH:mm:ss")}: Excalidraw patched in total ${i} files`,
);
}, 420000); //7 minutes
}
}
class MigrationPrompt extends Modal {
private plugin: ExcalidrawPlugin;
constructor(app: App, plugin: ExcalidrawPlugin) {
super(app);
this.plugin = plugin;
}
onOpen(): void {
this.titleEl.setText("Welcome to Excalidraw 1.2");
this.createForm();
}
onClose(): void {
this.contentEl.empty();
}
createForm(): void {
const div = this.contentEl.createDiv();
// div.addClass("excalidraw-prompt-div");
// div.style.maxWidth = "600px";
div.createEl("p", {
text: "This version comes with tons of new features and possibilities. Please read the description in Community Plugins to find out more.",
});
div.createEl("p", { text: "" }, (el) => {
el.innerHTML =
"Drawings you've created with version 1.1.x need to be converted to take advantage of the new features. You can also continue to use them in compatibility mode. " +
"During conversion your old *.excalidraw files will be replaced with new *.excalidraw.md files.";
});
div.createEl("p", { text: "" }, (el) => {
//files manually follow one of two options:
el.innerHTML =
"To convert your drawings you have the following options:<br><ul>" +
"<li>Click <code>CONVERT FILES</code> now to convert all of your *.excalidraw files, or if you prefer to make a backup first, then click <code>CANCEL</code>.</li>" +
"<li>In the Command Palette select <code>Excalidraw: Convert *.excalidraw files to *.excalidraw.md files</code></li>" +
"<li>Right click an <code>*.excalidraw</code> file in File Explorer and select one of the following options to convert files one by one: <ul>" +
"<li><code>*.excalidraw => *.excalidraw.md</code></li>" +
"<li><code>*.excalidraw => *.md (Logseq compatibility)</code>. This option will retain the original *.excalidraw file next to the new Obsidian format. " +
"Make sure you also enable <code>Compatibility features</code> in Settings for a full solution.</li></ul></li>" +
"<li>Open a drawing in compatibility mode and select <code>Convert to new format</code> from the <code>Options Menu</code></li></ul>";
});
div.createEl("p", {
text: "This message will only appear maximum 3 times in case you have *.excalidraw files in your Vault.",
});
const bConvert = div.createEl("button", { text: "CONVERT FILES" });
bConvert.onclick = () => {
this.plugin.convertExcalidrawToMD();
this.close();
};
const bCancel = div.createEl("button", { text: "CANCEL" });
bCancel.onclick = () => {
this.close();
};
}
}
class ImageElementNotice extends Modal {
private plugin: ExcalidrawPlugin;
private saveChanges: boolean = false;
constructor(app: App, plugin: ExcalidrawPlugin) {
super(app);
this.plugin = plugin;
}
onOpen(): void {
this.titleEl.setText("Image Elements have arrived!");
this.createForm();
}
async onClose() {
this.contentEl.empty();
if (!this.saveChanges) {
return;
}
await this.plugin.loadSettings();
this.plugin.settings.imageElementNotice = false;
this.plugin.saveSettings();
}
createForm(): void {
const div = this.contentEl.createDiv();
//div.addClass("excalidraw-prompt-div");
//div.style.maxWidth = "600px";
div.createEl("p", { text: "" }, (el) => {
el.innerHTML =
"Welcome to Obsidian-Excalidraw 1.4! I've added Image Elements. " +
"Please watch the video below to learn how to use this new feature.";
});
div.createEl("p", { text: "" }, (el) => {
el.innerHTML =
"<u>⚠ WARNING:</u> Opening new drawings with an older version of the plugin will lead to loss of images. " +
"Update the plugin on all your devices.";
});
div.createEl("p", { text: "" }, (el) => {
el.innerHTML =
"Since March, I have spent most of my free time building this plugin. Close to 75 workdays worth of my time (assuming 8-hour days). " +
"Some of you have already bought me a coffee. THANK YOU! Your support really means a lot to me! If you have not yet done so, please consider clicking the button below.";
});
const coffeeDiv = div.createDiv("coffee");
coffeeDiv.addClass("ex-coffee-div");
const coffeeLink = coffeeDiv.createEl("a", {
href: "https://ko-fi.com/zsolt",
});
const coffeeImg = coffeeLink.createEl("img", {
attr: {
src: "https://cdn.ko-fi.com/cdn/kofi3.png?v=3",
},
});
coffeeImg.height = 45;
div.createEl("p", { text: "" }, (el) => {
//files manually follow one of two options:
el.style.textAlign = "center";
el.innerHTML =
'<iframe width="560" height="315" src="https://www.youtube.com/embed/_c_0zpBJ4Xc?start=20" title="YouTube video player" ' +
'frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" ' +
"allowfullscreen></iframe>";
});
div.createEl("p", { text: "" }, (el) => {
//files manually follow one of two options:
el.style.textAlign = "right";
const bOk = el.createEl("button", { text: "OK - Don't show this again" });
bOk.onclick = () => {
this.saveChanges = true;
this.close();
};
const bCancel = el.createEl("button", {
text: "CANCEL - Read next time",
});
bCancel.onclick = () => {
this.saveChanges = false;
this.close();
};
});
}
*/
}

View File

@@ -1,6 +1,6 @@
import { Copy, Crop, Globe, RotateCcw, Scan, Settings, TextSelect } from "lucide-react";
import * as React from "react";
import { PenStyle } from "src/types/PenTypes";
import { PenStyle } from "src/types/penTypes";
export const ICONS = {
ExportImage: (

View File

@@ -1,8 +1,8 @@
import { customAlphabet } from "nanoid";
import { DeviceType } from "../types/types";
import { ExcalidrawLib } from "../ExcalidrawLib";
import { ExcalidrawLib } from "../types/excalidrawLib";
import { moment } from "obsidian";
import ExcalidrawPlugin from "src/main";
import ExcalidrawPlugin from "src/core/main";
import { DeviceType } from "src/types/types";
//This is only for backward compatibility because an early version of obsidian included an encoding to avoid fantom links from littering Obsidian graph view
declare const PLUGIN_VERSION:string;
export let EXCALIDRAW_PLUGIN: ExcalidrawPlugin = null;
@@ -27,6 +27,7 @@ export const ERROR_IFRAME_CONVERSION_CANCELED = "iframe conversion canceled";
declare const excalidrawLib: typeof ExcalidrawLib;
export const LOCALE = moment.locale();
export const CJK_FONTS = "CJK Fonts";
export const obsidianToExcalidrawMap: { [key: string]: string } = {
'en': 'en-US',
@@ -104,6 +105,7 @@ export let {
refreshTextDimensions,
getCSSFontDefinition,
loadSceneFonts,
loadMermaid,
} = excalidrawLib;
export function updateExcalidrawLib() {
@@ -129,6 +131,7 @@ export function updateExcalidrawLib() {
refreshTextDimensions,
getCSSFontDefinition,
loadSceneFonts,
loadMermaid,
} = excalidrawLib);
}
@@ -152,7 +155,12 @@ export const DEVICE: DeviceType = {
isAndroid: document.body.hasClass("is-android"),
};
export const ROOTELEMENTSIZE = (() => {
export let ROOTELEMENTSIZE: number = 16;
export function setRootElementSize(size?:number) {
if(size) {
ROOTELEMENTSIZE = size;
return;
}
const tempElement = document.createElement('div');
tempElement.style.fontSize = '1rem';
tempElement.style.display = 'none'; // Hide the element
@@ -161,7 +169,7 @@ export const ROOTELEMENTSIZE = (() => {
const pixelSize = parseFloat(computedStyle.fontSize);
document.body.removeChild(tempElement);
return pixelSize;
})();
};
export const nanoid = customAlphabet(
"1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",

View File

@@ -1,7 +1,7 @@
import { Extension } from "@codemirror/state";
import ExcalidrawPlugin from "src/main";
import ExcalidrawPlugin from "src/core/main";
import { HideTextBetweenCommentsExtension } from "./Fadeout";
import { debug, DEBUGGING } from "src/utils/DebugHelper";
import { debug, DEBUGGING } from "src/utils/debugHelper";
export const EDITOR_FADEOUT = "fadeOutExcalidrawMarkup";
const editorExtensions: {[key:string]:Extension}= {

View File

@@ -1,14 +1,14 @@
import "obsidian";
//import { ExcalidrawAutomate } from "./ExcalidrawAutomate";
//export ExcalidrawAutomate from "./ExcalidrawAutomate";
//export {ExcalidrawAutomate} from "./ExcaildrawAutomate";
export type { ExcalidrawBindableElement, ExcalidrawElement, FileId, FillStyle, StrokeRoundness, StrokeStyle } from "@zsviczian/excalidraw/types/excalidraw/element/types";
export type { Point } from "src/types/types";
export const getEA = (view?:any): any => {
try {
return window.ExcalidrawAutomate.getAPI(view);
} catch(e) {
console.log({message: "Excalidraw not available", fn: getEA});
return null;
}
import "obsidian";
//import { ExcalidrawAutomate } from "./ExcalidrawAutomate";
//export ExcalidrawAutomate from "./ExcalidrawAutomate";
//export {ExcalidrawAutomate} from "./ExcaildrawAutomate";
export type { ExcalidrawBindableElement, ExcalidrawElement, FileId, FillStyle, StrokeRoundness, StrokeStyle } from "@zsviczian/excalidraw/types/excalidraw/element/types";
export type { Point } from "src/types/types";
export const getEA = (view?:any): any => {
try {
return window.ExcalidrawAutomate.getAPI(view);
} catch(e) {
console.log({message: "Excalidraw not available", fn: getEA});
return null;
}
}

1441
src/core/main.ts Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,340 @@
import { WorkspaceLeaf, TFile, Editor, MarkdownView, MarkdownFileInfo, MetadataCache, App, EventRef, Menu, FileView } from "obsidian";
import { ExcalidrawElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { getLink } from "../../utils/fileUtils";
import { editorInsertText, getParentOfClass, setExcalidrawView } from "../../utils/obsidianUtils";
import ExcalidrawPlugin from "src/core/main";
import { DEBUGGING, debug } from "src/utils/debugHelper";
import { ExcalidrawAutomate } from "src/shared/ExcalidrawAutomate";
import { DEVICE, FRONTMATTER_KEYS, ICON_NAME, VIEW_TYPE_EXCALIDRAW } from "src/constants/constants";
import ExcalidrawView from "src/view/ExcalidrawView";
import { t } from "src/lang/helpers";
/**
* Registers event listeners for the plugin
* Must be constructed after the workspace is ready (onLayoutReady)
* Intended to be called from onLayoutReady in onload()
*/
export class EventManager {
private plugin: ExcalidrawPlugin;
private app: App;
public leafChangeTimeout: number|null = null;
private removeEventLisnters:(()=>void)[] = []; //only used if I register an event directly, not via Obsidian's registerEvent
private previouslyActiveLeaf: WorkspaceLeaf;
private splitViewLeafSwitchTimestamp: number = 0;
get settings() {
return this.plugin.settings;
}
get ea():ExcalidrawAutomate {
return this.plugin.ea;
}
get activeExcalidrawView() {
return this.plugin.activeExcalidrawView;
}
set activeExcalidrawView(view: ExcalidrawView) {
this.plugin.activeExcalidrawView = view;
}
private registerEvent(eventRef: EventRef): void {
this.plugin.registerEvent(eventRef);
}
constructor(plugin: ExcalidrawPlugin) {
this.plugin = plugin;
this.app = plugin.app;
}
destroy() {
if(this.leafChangeTimeout) {
window.clearTimeout(this.leafChangeTimeout);
this.leafChangeTimeout = null;
}
this.removeEventLisnters.forEach((removeEventListener) =>
removeEventListener(),
);
this.removeEventLisnters = [];
}
public async initialize() {
try {
await this.registerEvents();
} catch (e) {
console.error("Error registering event listeners", e);
}
this.plugin.logStartupEvent("Event listeners registered");
}
public isRecentSplitViewSwitch():boolean {
return (Date.now() - this.splitViewLeafSwitchTimestamp) < 3000;
}
public async registerEvents() {
await this.plugin.awaitInit();
this.registerEvent(this.app.workspace.on("editor-paste", this.onPasteHandler.bind(this)));
this.registerEvent(this.app.vault.on("rename", this.onRenameHandler.bind(this)));
this.registerEvent(this.app.vault.on("modify", this.onModifyHandler.bind(this)));
this.registerEvent(this.app.vault.on("delete", this.onDeleteHandler.bind(this)));
//save Excalidraw leaf and update embeds when switching to another leaf
this.registerEvent(this.plugin.app.workspace.on("active-leaf-change", this.onActiveLeafChangeHandler.bind(this)));
//File Save Trigger Handlers
//Save the drawing if the user clicks outside the Excalidraw Canvas
const onClickEventSaveActiveDrawing = this.onClickSaveActiveDrawing.bind(this);
this.app.workspace.containerEl.addEventListener("click", onClickEventSaveActiveDrawing);
this.removeEventLisnters.push(() => {
this.app.workspace.containerEl.removeEventListener("click", onClickEventSaveActiveDrawing)
});
this.registerEvent(this.app.workspace.on("file-menu", this.onFileMenuSaveActiveDrawing.bind(this)));
const metaCache: MetadataCache = this.app.metadataCache;
this.registerEvent(
metaCache.on("changed", (file, _, cache) =>
this.plugin.updateFileCache(file, cache?.frontmatter),
),
);
this.registerEvent(this.app.workspace.on("file-menu", this.onFileMenuHandler.bind(this)));
this.plugin.registerEvent(this.plugin.app.workspace.on("editor-menu", this.onEditorMenuHandler.bind(this)));
}
private onPasteHandler (evt: ClipboardEvent, editor: Editor, info: MarkdownView | MarkdownFileInfo ) {
if(evt.defaultPrevented) return
const data = evt.clipboardData.getData("text/plain");
if (!data) return;
if (data.startsWith(`{"type":"excalidraw/clipboard"`)) {
evt.preventDefault();
try {
const drawing = JSON.parse(data);
const hasOneTextElement = drawing.elements.filter((el:ExcalidrawElement)=>el.type==="text").length === 1;
if (!(hasOneTextElement || drawing.elements?.length === 1)) {
return;
}
const element = hasOneTextElement
? drawing.elements.filter((el:ExcalidrawElement)=>el.type==="text")[0]
: drawing.elements[0];
if (element.type === "image") {
const fileinfo = this.plugin.filesMaster.get(element.fileId);
if(fileinfo && fileinfo.path) {
let path = fileinfo.path;
const sourceFile = info.file;
const imageFile = this.app.vault.getAbstractFileByPath(path);
if(sourceFile && imageFile && imageFile instanceof TFile) {
path = this.app.metadataCache.fileToLinktext(imageFile,sourceFile.path);
}
editorInsertText(editor, getLink(this.plugin, {path}));
}
return;
}
if (element.type === "text") {
editorInsertText(editor, element.rawText);
return;
}
if (element.link) {
editorInsertText(editor, `${element.link}`);
return;
}
} catch (e) {
}
}
};
private onRenameHandler(file: TFile, oldPath: string) {
this.plugin.renameEventHandler(file, oldPath);
}
private onModifyHandler(file: TFile) {
this.plugin.modifyEventHandler(file);
}
private onDeleteHandler(file: TFile) {
this.plugin.deleteEventHandler(file);
}
public async onActiveLeafChangeHandler (leaf: WorkspaceLeaf) {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.onActiveLeafChangeHandler,`onActiveLeafChangeEventHandler`, leaf);
//https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/723
if (leaf.view && leaf.view.getViewType() === "pdf") {
this.plugin.lastPDFLeafID = leaf.id;
}
if(this.leafChangeTimeout) {
window.clearTimeout(this.leafChangeTimeout);
}
this.leafChangeTimeout = window.setTimeout(()=>{this.leafChangeTimeout = null;},1000);
if(this.settings.overrideObsidianFontSize) {
if(leaf.view && (leaf.view.getViewType() === VIEW_TYPE_EXCALIDRAW)) {
document.documentElement.style.fontSize = "";
}
}
const previouslyActiveEV = this.activeExcalidrawView;
const newActiveviewEV: ExcalidrawView =
leaf.view instanceof ExcalidrawView ? leaf.view : null;
this.activeExcalidrawView = newActiveviewEV;
const previousFile = (this.previouslyActiveLeaf?.view as FileView)?.file;
const currentFile = (leaf?.view as FileView).file;
//editing the same file in a different leaf
if(currentFile && (previousFile === currentFile)) {
if((this.previouslyActiveLeaf.view instanceof MarkdownView && leaf.view instanceof ExcalidrawView)) {
this.splitViewLeafSwitchTimestamp = Date.now();
}
}
this.previouslyActiveLeaf = leaf;
if (newActiveviewEV) {
this.plugin.addModalContainerObserver();
this.plugin.lastActiveExcalidrawFilePath = newActiveviewEV.file?.path;
} else {
this.plugin.removeModalContainerObserver();
}
//!Temporary hack
//https://discord.com/channels/686053708261228577/817515900349448202/1031101635784613968
if (DEVICE.isMobile && newActiveviewEV && !previouslyActiveEV) {
const navbar = document.querySelector("body>.app-container>.mobile-navbar");
if(navbar && navbar instanceof HTMLDivElement) {
navbar.style.position="relative";
}
}
if (DEVICE.isMobile && !newActiveviewEV && previouslyActiveEV) {
const navbar = document.querySelector("body>.app-container>.mobile-navbar");
if(navbar && navbar instanceof HTMLDivElement) {
navbar.style.position="";
}
}
//----------------------
//----------------------
if (previouslyActiveEV && previouslyActiveEV !== newActiveviewEV) {
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?.isDirty() && !previouslyActiveEV.semaphores?.viewunload) {
await previouslyActiveEV.save(true); //this will update transclusions in the drawing
}
}
if (previouslyActiveEV.file) {
this.plugin.triggerEmbedUpdates(previouslyActiveEV.file.path);
}
}
if (
newActiveviewEV &&
(!previouslyActiveEV || previouslyActiveEV.leaf !== leaf)
) {
//the user switched to a new leaf
//timeout gives time to the view being exited to finish saving
const f = newActiveviewEV.file;
if (newActiveviewEV.file) {
setTimeout(() => {
if (!newActiveviewEV || !newActiveviewEV._loaded) {
return;
}
if (newActiveviewEV.file?.path !== f?.path) {
return;
}
if (newActiveviewEV.activeLoader) {
return;
}
newActiveviewEV.loadSceneFiles();
}, 2000);
} //refresh embedded files
}
if (
newActiveviewEV && newActiveviewEV._loaded &&
newActiveviewEV.isLoaded && newActiveviewEV.excalidrawAPI &&
this.ea.onCanvasColorChangeHook
) {
this.ea.onCanvasColorChangeHook(
this.ea,
newActiveviewEV,
newActiveviewEV.excalidrawAPI.getAppState().viewBackgroundColor
);
}
//https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/300
if (this.plugin.popScope) {
this.plugin.popScope();
this.plugin.popScope = null;
}
if (newActiveviewEV) {
this.plugin.registerHotkeyOverrides();
}
}
//https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/551
private onClickSaveActiveDrawing(e: PointerEvent) {
if (
!this.activeExcalidrawView ||
!this.activeExcalidrawView?.isDirty() ||
e.target && ((e.target as Element).className === "excalidraw__canvas" ||
getParentOfClass((e.target as Element),"excalidraw-wrapper"))
) {
return;
}
this.activeExcalidrawView.save();
}
private onFileMenuSaveActiveDrawing () {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.onFileMenuSaveActiveDrawing,`onFileMenuSaveActiveDrawing`);
if (
!this.activeExcalidrawView ||
!this.activeExcalidrawView?.isDirty()
) {
return;
}
this.activeExcalidrawView.save();
};
private onFileMenuHandler(menu: Menu, file: TFile, source: string, leaf: WorkspaceLeaf) {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.onFileMenuHandler, `EventManager.onFileMenuHandler`, file, source, leaf);
if (!leaf) return;
const view = leaf.view;
if(!view || !(view instanceof MarkdownView)) return;
if (!(file instanceof TFile)) return;
const cache = this.app.metadataCache.getFileCache(file);
if (!cache?.frontmatter || !cache.frontmatter[FRONTMATTER_KEYS["plugin"].name]) return;
menu.addItem(item => {
item
.setTitle(t("OPEN_AS_EXCALIDRAW"))
.setIcon(ICON_NAME)
.setSection("pane")
.onClick(async () => {
await view.save();
this.plugin.excalidrawFileModes[leaf.id || file.path] = VIEW_TYPE_EXCALIDRAW;
setExcalidrawView(leaf);
})});
menu.items.unshift(menu.items.pop());
}
private onEditorMenuHandler(menu: Menu, editor: Editor, view: MarkdownView) {
if(!view || !(view instanceof MarkdownView)) return;
const file = view.file;
const leaf = view.leaf;
if (!view.file) return;
const cache = this.app.metadataCache.getFileCache(file);
if (!cache?.frontmatter || !cache.frontmatter[FRONTMATTER_KEYS["plugin"].name]) return;
menu.addItem(item => item
.setTitle(t("OPEN_AS_EXCALIDRAW"))
.setIcon(ICON_NAME)
.setSection("excalidraw")
.onClick(async () => {
await view.save();
this.plugin.excalidrawFileModes[leaf.id || file.path] = VIEW_TYPE_EXCALIDRAW;
setExcalidrawView(leaf);
})
);
}
}

View File

@@ -1,15 +1,15 @@
import { debug } from "src/utils/DebugHelper";
import { App, FrontMatterCache, MarkdownView, normalizePath, Notice, TAbstractFile, TFile, WorkspaceLeaf } from "obsidian";
import { debug } from "src/utils/debugHelper";
import { App, FrontMatterCache, MarkdownView, MetadataCache, normalizePath, Notice, TAbstractFile, TFile, WorkspaceLeaf } from "obsidian";
import { BLANK_DRAWING, DARK_BLANK_DRAWING, DEVICE, EXPORT_TYPES, FRONTMATTER, FRONTMATTER_KEYS, JSON_parse, nanoid, VIEW_TYPE_EXCALIDRAW } from "src/constants/constants";
import { Prompt, templatePromt } from "src/dialogs/Prompt";
import { changeThemeOfExcalidrawMD, ExcalidrawData, getMarkdownDrawingSection } from "src/ExcalidrawData";
import ExcalidrawView, { getTextMode } from "src/ExcalidrawView";
import ExcalidrawPlugin from "src/main";
import { DEBUGGING } from "src/utils/DebugHelper";
import { checkAndCreateFolder, download, getIMGFilename, getLink, getListOfTemplateFiles, getNewUniqueFilepath } from "src/utils/FileUtils";
import { PaneTarget } from "src/utils/ModifierkeyHelper";
import { getExcalidrawViews, getNewOrAdjacentLeaf, isObsidianThemeDark, openLeaf } from "src/utils/ObsidianUtils";
import { errorlog, getExportTheme } from "src/utils/Utils";
import { Prompt, templatePromt } from "src/shared/Dialogs/Prompt";
import { changeThemeOfExcalidrawMD, ExcalidrawData, getMarkdownDrawingSection } from "../../shared/ExcalidrawData";
import ExcalidrawView, { getTextMode } from "src/view/ExcalidrawView";
import ExcalidrawPlugin from "src/core/main";
import { DEBUGGING } from "src/utils/debugHelper";
import { checkAndCreateFolder, download, getIMGFilename, getLink, getListOfTemplateFiles, getNewUniqueFilepath } from "src/utils/fileUtils";
import { PaneTarget } from "src/utils/modifierkeyHelper";
import { getExcalidrawViews, getNewOrAdjacentLeaf, isObsidianThemeDark, openLeaf } from "src/utils/obsidianUtils";
import { errorlog, getExportTheme } from "src/utils/utils";
export class PluginFileManager {
private plugin: ExcalidrawPlugin;
@@ -25,6 +25,23 @@ export class PluginFileManager {
this.app = plugin.app;
}
public async initialize() {
await this.plugin.awaitInit();
const metaCache: MetadataCache = this.app.metadataCache;
metaCache.getCachedFiles().forEach((filename: string) => {
const fm = metaCache.getCache(filename)?.frontmatter;
if (
(fm && typeof fm[FRONTMATTER_KEYS["plugin"].name] !== "undefined") ||
filename.match(/\.excalidraw$/)
) {
this.updateFileCache(
this.app.vault.getAbstractFileByPath(filename) as TFile,
fm,
);
}
});
}
public isExcalidrawFile(f: TFile): boolean {
if(!f) return false;
if (f.extension === "excalidraw") {
@@ -255,7 +272,6 @@ export class PluginFileManager {
}
let leaf: WorkspaceLeaf;
if(location === "popout-window") {
//@ts-ignore (the api does not include x,y)
leaf = this.app.workspace.openPopoutLeaf(popoutLocation);
}
if(location === "new-tab") {
@@ -308,7 +324,7 @@ export class PluginFileManager {
const textElements = excalidrawData.elements?.filter(
(el: any) => el.type == "text",
);
let outString = `# Excalidraw Data\n## Text Elements\n`;
let outString = `# Excalidraw Data\n\n## Text Elements\n`;
let id: string;
for (const te of textElements) {
id = te.id;
@@ -356,7 +372,7 @@ export class PluginFileManager {
}
[EXPORT_TYPES, "excalidraw"].flat().forEach(async (ext: string) => {
const oldIMGpath = getIMGFilename(oldPath, ext);
const imgFile = app.vault.getAbstractFileByPath(
const imgFile = this.app.vault.getAbstractFileByPath(
normalizePath(oldIMGpath),
);
if (imgFile && imgFile instanceof TFile) {
@@ -367,7 +383,7 @@ export class PluginFileManager {
}
public async modifyEventHandler (file: TFile) {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.modifyEventHandler,`ExcalidrawPlugin.modifyEventHandler`, file);
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.modifyEventHandler,`FileManager.modifyEventHandler`, file);
const excalidrawViews = getExcalidrawViews(this.app);
excalidrawViews.forEach(async (excalidrawView) => {
if(excalidrawView.semaphores?.viewunload) {
@@ -386,11 +402,30 @@ export class PluginFileManager {
excalidrawView.semaphores.preventReload = false;
return;
}
//if the user hasn't touched the file for 5 minutes, don't synchronize, reload.
//this is to avoid complex sync scenarios of multiple remote changes outside an active collaboration session
// Avoid synchronizing or reloading if the user hasn't interacted with the file for 5 minutes.
// This prevents complex sync issues when multiple remote changes occur outside an active collaboration session.
// The following logic handles a rare edge case where:
// 1. The user opens an Excalidraw file.
// 2. Immediately splits the view without saving Excalidraw (since no changes were made).
// 3. Switches the new split view to Markdown, edits the file, and quickly returns to Excalidraw.
// 4. The "modify" event may fire while Excalidraw is active, triggering an unwanted reload and zoom reset.
// To address this:
// - We check if the user is currently editing the Markdown version of the Excalidraw file in a split view.
// - As a heuristic, we also check for recent leaf switches.
// This is not perfectly accurate (e.g., rapid switching between views within a few seconds),
// but it is sufficient to avoid most edge cases without introducing complexity.
// Edge case impact:
// - In extremely rare situations, an update arriving within the "recent switch" timeframe (e.g., from Obsidian Sync)
// might not trigger a reload. This is unlikely and an acceptable trade-off for better user experience.
const activeView = this.app.workspace.activeLeaf.view;
const isEditingMarkdownSideInSplitView = (activeView !== excalidrawView) &&
activeView instanceof MarkdownView && activeView.file === excalidrawView.file;
const isEditingMarkdownSideInSplitView = ((activeView !== excalidrawView) &&
activeView instanceof MarkdownView && activeView.file === excalidrawView.file) ||
(activeView === excalidrawView && this.plugin.isRecentSplitViewSwitch());
if(!isEditingMarkdownSideInSplitView && (excalidrawView.lastSaveTimestamp + 300000 < Date.now())) {
excalidrawView.reload(true, excalidrawView.file);

View File

@@ -1,8 +1,8 @@
import { debug, DEBUGGING } from "src/utils/DebugHelper";
import ExcalidrawPlugin from "src/main";
import { CustomMutationObserver } from "src/utils/DebugHelper";
import { getExcalidrawViews, isObsidianThemeDark } from "src/utils/ObsidianUtils";
import { App, TFile } from "obsidian";
import { debug, DEBUGGING } from "src/utils/debugHelper";
import ExcalidrawPlugin from "src/core/main";
import { CustomMutationObserver } from "src/utils/debugHelper";
import { getExcalidrawViews, isObsidianThemeDark } from "src/utils/obsidianUtils";
import { App, Notice, TFile } from "obsidian";
export class ObserverManager {
private plugin: ExcalidrawPlugin;
@@ -14,16 +14,45 @@ export class ObserverManager {
private workspaceDrawerRightObserver: MutationObserver | CustomMutationObserver;
private activeViewDoc: Document;
get settings() {
return this.plugin.settings;
}
constructor(plugin: ExcalidrawPlugin) {
this.plugin = plugin;
this.app = plugin.app;
if(this.settings.matchThemeTrigger) this.addThemeObserver();
this.experimentalFileTypeDisplayToggle(this.settings.experimentalFileType);
this.addModalContainerObserver();
}
get settings() {
return this.plugin.settings;
public initialize() {
try {
if(this.settings.matchThemeTrigger) this.addThemeObserver();
this.experimentalFileTypeDisplayToggle(this.settings.experimentalFileType);
this.addModalContainerObserver();
} catch (e) {
new Notice("Error adding ObserverManager", 6000);
console.error("Error adding ObserverManager", e);
}
this.plugin.logStartupEvent("ObserverManager added");
}
public destroy() {
this.removeThemeObserver();
this.removeModalContainerObserver();
if (this.workspaceDrawerLeftObserver) {
this.workspaceDrawerLeftObserver.disconnect();
}
if (this.workspaceDrawerRightObserver) {
this.workspaceDrawerRightObserver.disconnect();
}
if (this.fileExplorerObserver) {
this.fileExplorerObserver.disconnect();
}
if (this.workspaceDrawerRightObserver) {
this.workspaceDrawerRightObserver.disconnect();
}
if (this.workspaceDrawerLeftObserver) {
this.workspaceDrawerLeftObserver.disconnect();
}
}
public addThemeObserver() {
@@ -183,17 +212,46 @@ export class ObserverManager {
this.modalContainerObserver = null;
}
public destroy() {
this.removeThemeObserver();
this.removeModalContainerObserver();
if (this.workspaceDrawerLeftObserver) {
this.workspaceDrawerLeftObserver.disconnect();
}
if (this.workspaceDrawerRightObserver) {
this.workspaceDrawerRightObserver.disconnect();
}
if (this.fileExplorerObserver) {
this.fileExplorerObserver.disconnect();
private addWorkspaceDrawerObserver() {
//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.plugin.activeExcalidrawView ||
!this.plugin.activeExcalidrawView?.isDirty()
) {
return;
}
this.plugin.activeExcalidrawView.save();
};
const options = {
attributeOldValue: true,
attributeFilter: ["style"],
};
if (leftWorkspaceDrawer) {
this.workspaceDrawerLeftObserver = DEBUGGING
? new CustomMutationObserver(action, "slidingDrawerLeftObserver")
: new MutationObserver(action);
this.workspaceDrawerLeftObserver.observe(leftWorkspaceDrawer, options);
}
if (rightWorkspaceDrawer) {
this.workspaceDrawerRightObserver = DEBUGGING
? new CustomMutationObserver(action, "slidingDrawerRightObserver")
: new MutationObserver(action);
this.workspaceDrawerRightObserver.observe(
rightWorkspaceDrawer,
options,
);
}
}
}
}

View File

@@ -1,18 +1,31 @@
import { ExcalidrawLib } from "../ExcalidrawLib";
import { Packages } from "../types/types";
import { debug, DEBUGGING } from "../utils/DebugHelper";
import { updateExcalidrawLib } from "src/constants/constants";
import { ExcalidrawLib } from "../../types/excalidrawLib";
import { Packages } from "../../types/types";
import { debug, DEBUGGING } from "../../utils/debugHelper";
import { Notice } from "obsidian";
import ExcalidrawPlugin from "src/core/main";
declare let REACT_PACKAGES:string;
declare let react:any;
declare let reactDOM:any;
declare let excalidrawLib: typeof ExcalidrawLib;
declare const unpackExcalidraw: Function;
export class PackageManager {
private packageMap: Map<Window, Packages> = new Map<Window, Packages>();
private EXCALIDRAW_PACKAGE: string;
constructor() {
this.packageMap.set(window,{react, reactDOM, excalidrawLib});
constructor(plugin: ExcalidrawPlugin) {
try {
this.EXCALIDRAW_PACKAGE = unpackExcalidraw();
excalidrawLib = window.eval.call(window,`(function() {${this.EXCALIDRAW_PACKAGE};return ExcalidrawLib;})()`);
updateExcalidrawLib();
this.setPackage(window,{react, reactDOM, excalidrawLib});
} catch (e) {
new Notice("Error loading the Excalidraw package", 6000);
console.error("Error loading the Excalidraw package", e);
}
plugin.logStartupEvent("Excalidraw package unpacked");
}
public setPackage(window: Window, pkg: Packages) {
@@ -29,7 +42,7 @@ export class PackageManager {
if(this.packageMap.has(win)) {
return this.packageMap.get(win);
}
const {react:r, reactDOM:rd, excalidrawLib:e} = win.eval.call(win,
`(function() {
${REACT_PACKAGES + this.EXCALIDRAW_PACKAGE};
@@ -76,5 +89,9 @@ export class PackageManager {
delete p.react;
});
this.packageMap.clear();
this.EXCALIDRAW_PACKAGE = "";
react = null;
reactDOM = null;
excalidrawLib = null;
}
}

View File

@@ -1,7 +1,7 @@
import { WorkspaceWindow } from "obsidian";
import ExcalidrawPlugin from "src/main";
import { getAllWindowDocuments } from "./ObsidianUtils";
import { DEBUGGING, debug } from "./DebugHelper";
import ExcalidrawPlugin from "src/core/main";
import { getAllWindowDocuments } from "../../utils/obsidianUtils";
import { DEBUGGING, debug } from "../../utils/debugHelper";
export let REM_VALUE = 16;

View File

@@ -10,38 +10,37 @@ import {
TextComponent,
TFile,
} from "obsidian";
import { GITHUB_RELEASES } from "./constants/constants";
import { t } from "./lang/helpers";
import type ExcalidrawPlugin from "./main";
import { PenStyle } from "./types/PenTypes";
import { DynamicStyle, GridSettings } from "./types/types";
import { PreviewImageType } from "./utils/UtilTypes";
import { setDynamicStyle } from "./utils/DynamicStyling";
import { GITHUB_RELEASES, setRootElementSize } from "src/constants/constants";
import { t } from "src/lang/helpers";
import type ExcalidrawPlugin from "src/core/main";
import { PenStyle } from "src/types/penTypes";
import { DynamicStyle, GridSettings } from "src/types/types";
import { PreviewImageType } from "src/types/utilTypes";
import { setDynamicStyle } from "src/utils/dynamicStyling";
import {
getDrawingFilename,
getEmbedFilename,
} from "./utils/FileUtils";
import { PENS } from "./utils/Pens";
} from "src/utils/fileUtils";
import { PENS } from "src/utils/pens";
import {
addIframe,
fragWithHTML,
setLeftHandedMode,
} from "./utils/Utils";
import { imageCache } from "./utils/ImageCache";
import { ConfirmationPrompt } from "./dialogs/Prompt";
import { EmbeddableMDCustomProps } from "./dialogs/EmbeddableSettings";
import { EmbeddalbeMDFileCustomDataSettingsComponent } from "./dialogs/EmbeddableMDFileCustomDataSettingsComponent";
import { startupScript } from "./constants/starutpscript";
import { ModifierKeySet, ModifierSetType } from "./utils/ModifierkeyHelper";
import { ModifierKeySettingsComponent } from "./dialogs/ModifierKeySettings";
import { ANNOTATED_PREFIX, CROPPED_PREFIX } from "./utils/CarveOut";
import { EDITOR_FADEOUT } from "./CodeMirrorExtension/EditorHandler";
import { setDebugging } from "./utils/DebugHelper";
import { Rank } from "./menu/ActionIcons";
} from "src/utils/utils";
import { imageCache } from "src/shared/ImageCache";
import { ConfirmationPrompt } from "src/shared/Dialogs/Prompt";
import { EmbeddableMDCustomProps } from "src/shared/Dialogs/EmbeddableSettings";
import { EmbeddalbeMDFileCustomDataSettingsComponent } from "src/shared/Dialogs/EmbeddableMDFileCustomDataSettingsComponent";
import { startupScript } from "src/constants/starutpscript";
import { ModifierKeySet, ModifierSetType } from "src/utils/modifierkeyHelper";
import { ModifierKeySettingsComponent } from "src/shared/Dialogs/ModifierKeySettings";
import { ANNOTATED_PREFIX, CROPPED_PREFIX } from "src/utils/carveout";
import { EDITOR_FADEOUT } from "src/core/editor/EditorHandler";
import { setDebugging } from "src/utils/debugHelper";
import { Rank } from "src/constants/actionIcons";
import { TAG_AUTOEXPORT, TAG_MDREADINGMODE, TAG_PDFEXPORT } from "src/constants/constSettingsTags";
import { HotkeyEditor } from "./dialogs/HotkeyEditor";
import { getExcalidrawViews } from "./utils/ObsidianUtils";
import de from "./lang/locale/de";
import { HotkeyEditor } from "src/shared/Dialogs/HotkeyEditor";
import { getExcalidrawViews } from "src/utils/obsidianUtils";
export interface ExcalidrawSettings {
folder: string;
@@ -521,8 +520,10 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
async hide() {
if(this.plugin.settings.overrideObsidianFontSize) {
document.documentElement.style.fontSize = "";
setRootElementSize(16);
} else if(!document.documentElement.style.fontSize) {
document.documentElement.style.fontSize = getComputedStyle(document.body).getPropertyValue("--font-text-size");
setRootElementSize();
}
this.plugin.settings.scriptFolderPath = normalizePath(

View File

@@ -1,7 +1,32 @@
//Solution copied from obsidian-kanban: https://github.com/mgmeyers/obsidian-kanban/blob/44118e25661bff9ebfe54f71ae33805dc88ffa53/src/lang/helpers.ts
import { moment } from "obsidian";
import { errorlog } from "src/utils/Utils";
import { LOCALE } from "src/constants/constants";
import en from "./locale/en";
declare const PLUGIN_LANGUAGES: Record<string, string>;
declare var LZString: any;
let locale: Partial<typeof en> | null = null;
function loadLocale(lang: string): Partial<typeof en> {
if (Object.keys(PLUGIN_LANGUAGES).includes(lang)) {
const decompressed = LZString.decompressFromBase64(PLUGIN_LANGUAGES[lang]);
let x = {};
eval(decompressed);
return x;
} else {
return en;
}
}
export function t(str: keyof typeof en): string {
if (!locale) {
locale = loadLocale(LOCALE);
}
return (locale && locale[str]) || en[str];
}
/*
import ar from "./locale/ar";
import cz from "./locale/cz";
import da from "./locale/da";
@@ -51,11 +76,4 @@ const localeMap: { [k: string]: Partial<typeof en> } = {
tr,
"zh-cn": zhCN,
"zh-tw": zhTW,
};
const locale = localeMap[LOCALE];
export function t(str: keyof typeof en): string {
return (locale && locale[str]) || en[str];
}
};*/

View File

@@ -1,12 +1,11 @@
import { FILE } from "dns";
import {
DEVICE,
FRONTMATTER_KEYS,
CJK_FONTS,
} from "src/constants/constants";
import { TAG_AUTOEXPORT, TAG_MDREADINGMODE, TAG_PDFEXPORT } from "src/constants/constSettingsTags";
import { labelALT, labelCTRL, labelMETA, labelSHIFT } from "src/utils/ModifierkeyHelper";
import { labelALT, labelCTRL, labelMETA, labelSHIFT } from "src/utils/modifierkeyHelper";
const CJK_FONTS = "CJK Fonts";
declare const PLUGIN_VERSION:string;
// English
@@ -111,6 +110,7 @@ export default {
SELECT_LINK_TO_OPEN: "Select a link to open",
//ExcalidrawView.ts
ERROR_CANT_READ_FILEPATH: "Error, can't read file path. Importing file instead",
NO_SEARCH_RESULT: "Didn't find a matching element in the drawing",
FORCE_SAVE_ABORTED: "Force Save aborted because saving is in progress",
LINKLIST_SECOND_ORDER_LINK: "Second Order Link",
@@ -974,4 +974,30 @@ FILENAME_HEAD: "Filename",
//Utils.ts
UPDATE_AVAILABLE: `A newer version of Excalidraw is available in Community Plugins.\n\nYou are using ${PLUGIN_VERSION}.\nThe latest is`,
ERROR_PNG_TOO_LARGE: "Error exporting PNG - PNG too large, try a smaller resolution",
//modifierkeyHelper.ts
// WebBrowserDragAction
WEB_DRAG_IMPORT_IMAGE: "Import Image to Vault",
WEB_DRAG_IMAGE_URL: "Insert Image or YouTube Thumbnail with URL",
WEB_DRAG_LINK: "Insert Link",
WEB_DRAG_EMBEDDABLE: "Insert Interactive-Frame",
// LocalFileDragAction
LOCAL_DRAG_IMPORT: "Import external file or reuse existing file if path is from the Vault",
LOCAL_DRAG_IMAGE: "Insert Image: with local URI or internal-link if from Vault",
LOCAL_DRAG_LINK: "Insert Link: local URI or internal-link if from Vault",
LOCAL_DRAG_EMBEDDABLE: "Insert Interactive-Frame: local URI or internal-link if from Vault",
// InternalDragAction
INTERNAL_DRAG_IMAGE: "Insert Image",
INTERNAL_DRAG_IMAGE_FULL: "Insert Image @100%",
INTERNAL_DRAG_LINK: "Insert Link",
INTERNAL_DRAG_EMBEDDABLE: "Insert Interactive-Frame",
// LinkClickAction
LINK_CLICK_ACTIVE: "Open in current active window",
LINK_CLICK_NEW_PANE: "Open in a new adjacent window",
LINK_CLICK_POPOUT: "Open in a popout window",
LINK_CLICK_NEW_TAB: "Open in a new tab",
LINK_CLICK_MD_PROPS: "Show the Markdown image-properties dialog (only relevant if you have embedded a markdown document as an image)",
};

View File

@@ -1,9 +1,6 @@
import {
DEVICE,
FRONTMATTER_KEYS,
} from "src/constants/constants";
import { DEVICE, FRONTMATTER_KEYS, CJK_FONTS } from "src/constants/constants";
import { TAG_AUTOEXPORT, TAG_MDREADINGMODE, TAG_PDFEXPORT } from "src/constants/constSettingsTags";
import { labelALT, labelCTRL, labelMETA, labelSHIFT } from "src/utils/ModifierkeyHelper";
import { labelALT, labelCTRL, labelMETA, labelSHIFT } from "src/utils/modifierkeyHelper";
// русский
export default {

View File

@@ -1,12 +1,11 @@
import { FILE } from "dns";
import {
DEVICE,
FRONTMATTER_KEYS,
CJK_FONTS
} from "src/constants/constants";
import { TAG_AUTOEXPORT, TAG_MDREADINGMODE, TAG_PDFEXPORT } from "src/constants/constSettingsTags";
import { labelALT, labelCTRL, labelMETA, labelSHIFT } from "src/utils/ModifierkeyHelper";
import { labelALT, labelCTRL, labelMETA, labelSHIFT } from "src/utils/modifierkeyHelper";
const CJK_FONTS = "CJK Fonts";
declare const PLUGIN_VERSION:string;
// 简体中文
@@ -111,6 +110,7 @@ export default {
SELECT_LINK_TO_OPEN: "选择要打开的链接",
//ExcalidrawView.ts
ERROR_CANT_READ_FILEPATH : "错误,无法读取文件路径。正在改为导入文件",
NO_SEARCH_RESULT: "在绘图中未找到匹配的元素",
FORCE_SAVE_ABORTED: "自动保存被中止,因为文件正在保存中",
LINKLIST_SECOND_ORDER_LINK: "二级链接",
@@ -974,4 +974,30 @@ FILENAME_HEAD: "文件名",
//Utils.ts
UPDATE_AVAILABLE: `Excalidraw 的新版本已在社区插件中可用。\n\n您正在使用 ${PLUGIN_VERSION}\n最新版本是`,
ERROR_PNG_TOO_LARGE: "导出 PNG 时出错 - PNG 文件过大,请尝试较小的分辨率",
};
// ModifierkeyHelper.ts
// WebBrowserDragAction
WEB_DRAG_IMPORT_IMAGE : "导入图片到 Vault" ,
WEB_DRAG_IMAGE_URL : "通过 URL 插入图片或 YouTube 缩略图" ,
WEB_DRAG_LINK : "插入链接" ,
WEB_DRAG_EMBEDDABLE : "插入交互框架" ,
// LocalFileDragAction
LOCAL_DRAG_IMPORT : "导入外部文件,或在路径来自 Vault 时复用现有文件" ,
LOCAL_DRAG_IMAGE : "插入图片:使用本地 URI或在路径来自 Vault 时使用内部链接" ,
LOCAL_DRAG_LINK : "插入链接:使用本地 URI或在路径来自 Vault 时使用内部链接" ,
LOCAL_DRAG_EMBEDDABLE : "插入交互框架:使用本地 URI或在路径来自 Vault 时使用内部链接" ,
// InternalDragAction
INTERNAL_DRAG_IMAGE : "插入图片" ,
INTERNAL_DRAG_IMAGE_FULL : "插入图片100% 尺寸)" ,
INTERNAL_DRAG_LINK : "插入链接" ,
INTERNAL_DRAG_EMBEDDABLE : "插入交互框架" ,
// LinkClickAction
LINK_CLICK_ACTIVE : "在当前活动窗口中打开" ,
LINK_CLICK_NEW_PANE : "在相邻的新窗口中打开" ,
LINK_CLICK_POPOUT : "在弹出窗口中打开" ,
LINK_CLICK_NEW_TAB : "在新标签页中打开" ,
LINK_CLICK_MD_PROPS : "显示 Markdown 图片属性对话框(仅在嵌入 Markdown 文档为图片时适用)" ,
};

File diff suppressed because it is too large Load Diff

View File

@@ -3,10 +3,11 @@ import { BinaryFileData } from "@zsviczian/excalidraw/types/excalidraw/types";
import { Mutable } from "@zsviczian/excalidraw/types/excalidraw/utility-types";
import { Notice } from "obsidian";
import { getEA } from "src";
import { ExcalidrawAutomate, cloneElement } from "src/ExcalidrawAutomate";
import { ExportSettings } from "src/ExcalidrawView";
import { getEA } from "src/core";
import { ExcalidrawAutomate, cloneElement } from "src/shared/ExcalidrawAutomate";
import { ExportSettings } from "src/view/ExcalidrawView";
import { nanoid } from "src/constants/constants";
import { svgToBase64 } from "../utils/utils";
export class CropImage {
private imageEA: ExcalidrawAutomate;
@@ -170,7 +171,7 @@ export class CropImage {
1 // image quality (0 - 1)
);
};
image.src = `data:image/svg+xml;base64,${btoa(unescape(encodeURIComponent(svgData)))}`;
image.src = svgToBase64(svgData);
});
}

View File

@@ -1,6 +1,6 @@
import { Setting, ToggleComponent } from "obsidian";
import { EmbeddableMDCustomProps } from "./EmbeddableSettings";
import { fragWithHTML } from "src/utils/Utils";
import { fragWithHTML } from "src/utils/utils";
import { t } from "src/lang/helpers";
export class EmbeddalbeMDFileCustomDataSettingsComponent {

View File

@@ -1,16 +1,16 @@
import { ExcalidrawEmbeddableElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { Mutable } from "@zsviczian/excalidraw/types/excalidraw/utility-types";
import { Modal, Notice, Setting, TFile, ToggleComponent } from "obsidian";
import { getEA } from "src";
import { ExcalidrawAutomate } from "src/ExcalidrawAutomate";
import ExcalidrawView from "src/ExcalidrawView";
import { getEA } from "src/core";
import { ExcalidrawAutomate } from "src/shared/ExcalidrawAutomate";
import ExcalidrawView from "src/view/ExcalidrawView";
import { t } from "src/lang/helpers";
import ExcalidrawPlugin from "src/main";
import { getNewUniqueFilepath, getPathWithoutExtension, splitFolderAndFilename } from "src/utils/FileUtils";
import { addAppendUpdateCustomData, fragWithHTML } from "src/utils/Utils";
import ExcalidrawPlugin from "src/core/main";
import { getNewUniqueFilepath, getPathWithoutExtension, splitFolderAndFilename } from "src/utils/fileUtils";
import { addAppendUpdateCustomData, fragWithHTML } from "src/utils/utils";
import { getYouTubeStartAt, isValidYouTubeStart, isYouTube, updateYouTubeStartTime } from "src/utils/YoutTubeUtils";
import { EmbeddalbeMDFileCustomDataSettingsComponent } from "./EmbeddableMDFileCustomDataSettingsComponent";
import { isWinCTRLorMacCMD } from "src/utils/ModifierkeyHelper";
import { isWinCTRLorMacCMD } from "src/utils/modifierkeyHelper";
import { ExcalidrawImperativeAPI } from "@zsviczian/excalidraw/types/excalidraw/types";
export type EmbeddableMDCustomProps = {

View File

@@ -1,11 +1,11 @@
import { ExcalidrawImperativeAPI } from "@zsviczian/excalidraw/types/excalidraw/types";
import { Modal, Setting, TFile } from "obsidian";
import { getEA } from "src";
import { getEA } from "src/core";
import { DEVICE } from "src/constants/constants";
import { ExcalidrawAutomate } from "src/ExcalidrawAutomate";
import ExcalidrawView from "src/ExcalidrawView";
import ExcalidrawPlugin from "src/main";
import { fragWithHTML, getExportPadding, getExportTheme, getPNGScale, getWithBackground, shouldEmbedScene } from "src/utils/Utils";
import { ExcalidrawAutomate } from "src/shared/ExcalidrawAutomate";
import ExcalidrawView from "src/view/ExcalidrawView";
import ExcalidrawPlugin from "src/core/main";
import { fragWithHTML, getExportPadding, getExportTheme, getPNGScale, getWithBackground, shouldEmbedScene } from "src/utils/utils";
export class ExportDialog extends Modal {
private ea: ExcalidrawAutomate;

View File

@@ -1,11 +1,11 @@
import { ExcalidrawAutomate } from "src/ExcalidrawAutomate";
import { ExcalidrawAutomate } from "src/shared/ExcalidrawAutomate";
import { t } from "src/lang/helpers";
export const showFrameSettings = (ea: ExcalidrawAutomate) => {
const {enabled, clip, name, outline} = ea.getExcalidrawAPI().getAppState().frameRendering;
// Create modal dialog
const frameSettingsModal = new ea.obsidian.Modal(app);
const frameSettingsModal = new ea.obsidian.Modal(ea.plugin.app);
frameSettingsModal.onOpen = () => {
const {contentEl} = frameSettingsModal;

View File

@@ -1,9 +1,9 @@
import { BaseComponent, Setting, Modifier } from 'obsidian';
import { DEVICE } from 'src/constants/constants';
import { t } from 'src/lang/helpers';
import { ExcalidrawSettings } from 'src/settings';
import { modifierLabel } from 'src/utils/ModifierkeyHelper';
import { fragWithHTML } from 'src/utils/Utils';
import { ExcalidrawSettings } from 'src/core/settings';
import { modifierLabel } from 'src/utils/modifierkeyHelper';
import { fragWithHTML } from 'src/utils/utils';
export class HotkeyEditor extends BaseComponent {
private settings: ExcalidrawSettings;

View File

@@ -1,10 +1,10 @@
import { App, FuzzySuggestModal, TFile } from "obsidian";
import { REG_LINKINDEX_INVALIDCHARS } from "../constants/constants";
import ExcalidrawView from "../ExcalidrawView";
import { t } from "../lang/helpers";
import ExcalidrawPlugin from "../main";
import { getEA } from "src";
import { ExcalidrawAutomate } from "src/ExcalidrawAutomate";
import { REG_LINKINDEX_INVALIDCHARS } from "../../constants/constants";
import ExcalidrawView from "../../view/ExcalidrawView";
import { t } from "../../lang/helpers";
import ExcalidrawPlugin from "../../core/main";
import { getEA } from "src/core";
import { ExcalidrawAutomate } from "src/shared/ExcalidrawAutomate";
export class ImportSVGDialog extends FuzzySuggestModal<TFile> {
public plugin: ExcalidrawPlugin;

View File

@@ -1,6 +1,6 @@
import { App, FuzzySuggestModal, TFile } from "obsidian";
import { REG_LINKINDEX_INVALIDCHARS } from "../constants/constants";
import { t } from "../lang/helpers";
import { REG_LINKINDEX_INVALIDCHARS } from "../../constants/constants";
import { t } from "../../lang/helpers";
export class InsertCommandDialog extends FuzzySuggestModal<TFile> {
private addText: Function;

View File

@@ -1,10 +1,10 @@
import { App, FuzzySuggestModal, TFile } from "obsidian";
import { scaleToFullsizeModifier } from "src/utils/ModifierkeyHelper";
import { DEVICE, IMAGE_TYPES, REG_LINKINDEX_INVALIDCHARS } from "../constants/constants";
import ExcalidrawView from "../ExcalidrawView";
import { t } from "../lang/helpers";
import ExcalidrawPlugin from "../main";
import { getEA } from "src";
import { FuzzySuggestModal, TFile } from "obsidian";
import { scaleToFullsizeModifier } from "src/utils/modifierkeyHelper";
import { DEVICE, IMAGE_TYPES, REG_LINKINDEX_INVALIDCHARS } from "../../constants/constants";
import ExcalidrawView from "../../view/ExcalidrawView";
import { t } from "../../lang/helpers";
import ExcalidrawPlugin from "../../core/main";
import { getEA } from "src/core";
export class InsertImageDialog extends FuzzySuggestModal<TFile> {
public plugin: ExcalidrawPlugin;

View File

@@ -1,8 +1,8 @@
import { FuzzyMatch, FuzzySuggestModal, setIcon } from "obsidian";
import { AUDIO_TYPES, CODE_TYPES, ICON_NAME, IMAGE_TYPES, REG_LINKINDEX_INVALIDCHARS, VIDEO_TYPES } from "../constants/constants";
import { t } from "../lang/helpers";
import ExcalidrawPlugin from "src/main";
import { getLink } from "src/utils/FileUtils";
import { AUDIO_TYPES, CODE_TYPES, ICON_NAME, IMAGE_TYPES, REG_LINKINDEX_INVALIDCHARS, VIDEO_TYPES } from "../../constants/constants";
import { t } from "../../lang/helpers";
import ExcalidrawPlugin from "src/core/main";
import { getLink } from "src/utils/fileUtils";
import { LinkSuggestion } from "src/types/types";

View File

@@ -1,8 +1,8 @@
import { App, FuzzySuggestModal, TFile } from "obsidian";
import ExcalidrawView from "../ExcalidrawView";
import { t } from "../lang/helpers";
import ExcalidrawPlugin from "../main";
import { getEA } from "src";
import { FuzzySuggestModal, TFile } from "obsidian";
import ExcalidrawView from "../../view/ExcalidrawView";
import { t } from "../../lang/helpers";
import ExcalidrawPlugin from "../../core/main";
import { getEA } from "src/core";
export class InsertMDDialog extends FuzzySuggestModal<TFile> {
public plugin: ExcalidrawPlugin;

View File

@@ -1,11 +1,11 @@
import { ButtonComponent, TFile, ToggleComponent } from "obsidian";
import ExcalidrawView from "../ExcalidrawView";
import ExcalidrawPlugin from "../main";
import { getPDFDoc } from "src/utils/FileUtils";
import ExcalidrawView from "../../view/ExcalidrawView";
import ExcalidrawPlugin from "../../core/main";
import { getPDFDoc } from "src/utils/fileUtils";
import { Modal, Setting, TextComponent } from "obsidian";
import { FileSuggestionModal } from "../Components/Suggesters/FileSuggestionModal";
import { getEA } from "src";
import { ExcalidrawAutomate } from "src/ExcalidrawAutomate";
import { FileSuggestionModal } from "../Suggesters/FileSuggestionModal";
import { getEA } from "src/core";
import { ExcalidrawAutomate } from "src/shared/ExcalidrawAutomate";
import { ExcalidrawImperativeAPI } from "@zsviczian/excalidraw/types/excalidraw/types";
import { t } from "src/lang/helpers";

View File

@@ -17,6 +17,31 @@ I develop this plugin as a hobby, spending my free time doing this. If you find
<div class="ex-coffee-div"><a href="https://ko-fi.com/zsolt"><img src="https://storage.ko-fi.com/cdn/kofi6.png?v=6" border="0" alt="Buy Me a Coffee at ko-fi.com" height=45></a></div>
`,
"2.7.1":`
## Fixed
- Deleting excalidraw file from file system while it is open in fullscreen mode in Obsidian causes Obsidian to be stuck in full-screen view [#2161](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2161)
- Chinese fonts are not rendered in LaTeX statements [#2162](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2162)
- Since Electron 32 (newer Obsidian Desktop installers) drag and drop links from Finder or OS File Explorer did not work. [Electron breaking change](https://www.electronjs.org/docs/latest/breaking-changes#removed-filepath). This is now fixed
- Addressed unnecessary image reloads when changing windows in Obsidian
`,
"2.7.0":`
## Fixed
- Various Markdown embeddable "fuzziness":
- Fixed issues with appearance settings and edit mode toggling when single-click editing is enabled.
- Ensured embeddable file editing no longer gets interrupted unexpectedly.
- **Hover Preview**: Disabled hover preview for back-of-the-note cards to reduce distractions.
- **Settings Save**: Fixed an issue where plugin settings unnecessarily saved on every startup.
## New Features
- **Image Cropping Snaps to Objects**: When snapping is enabled in the scene, image cropping now aligns to nearby objects.
- **Session Persistence for Pen Mode**: Excalidraw remembers the last pen mode when switching between drawings within the same session.
## Refactoring
- **Mermaid Diagrams**: Excalidraw now uses its own Mermaid package, breaking future dependencies on Obsidian's Mermaid updates. This ensures stability and includes all fixes and improvements made to Excalidraw Mermaid since February 2024. The plugin file size has increased slightly, but this change significantly improves maintainability while remaining invisible to users.
- **MathJax Optimization**: MathJax (LaTeX equation SVG image generation) now loads only on demand, with the package compressed to minimize the startup and file size impact caused by the inclusion of Mermaid.
- **On-Demand Language Loading**: Non-English language files are now compressed and load only when needed, counterbalancing the increase in file size due to Mermaid and improving load speeds.
- **Codebase Restructuring**: Improved type safety by removing many ${String.fromCharCode(96)}//@ts-ignore${String.fromCharCode(96)} commands and enhancing modularity. Introduced new management classes: **CommandManager**, **EventManager**, **PluginFileManager**, **ObserverManager**, and **PackageManager**. Further restructuring is planned for upcoming releases to improve maintainability and stability.
`,
"2.6.8":`
## New
- **QoL improvements**:

View File

@@ -1,7 +1,7 @@
import { Setting } from "obsidian";
import { DEVICE } from "src/constants/constants";
import { t } from "src/lang/helpers";
import { ModifierKeySet, ModifierSetType, modifierKeyTooltipMessages } from "src/utils/ModifierkeyHelper";
import { ModifierKeySet, ModifierSetType, modifierKeyTooltipMessages } from "src/utils/modifierkeyHelper";
type ModifierKeyCategories = Partial<{
[modifierSetType in ModifierSetType]: string;

View File

@@ -1,7 +1,7 @@
import { App, FuzzySuggestModal, TFile } from "obsidian";
import ExcalidrawPlugin from "../main";
import { EMPTY_MESSAGE } from "../constants/constants";
import { t } from "../lang/helpers";
import ExcalidrawPlugin from "../../core/main";
import { EMPTY_MESSAGE } from "../../constants/constants";
import { t } from "../../lang/helpers";
export enum openDialogAction {
openFile,

View File

@@ -1,13 +1,13 @@
import { ExcalidrawImperativeAPI } from "@zsviczian/excalidraw/types/excalidraw/types";
import { ColorComponent, Modal, Setting, TextComponent, ToggleComponent } from "obsidian";
import { COLOR_NAMES } from "src/constants/constants";
import ExcalidrawView from "src/ExcalidrawView";
import ExcalidrawPlugin from "src/main";
import { setPen } from "src/menu/ObsidianMenu";
import { ExtendedFillStyle, PenType } from "src/types/PenTypes";
import { getExcalidrawViews } from "src/utils/ObsidianUtils";
import { PENS } from "src/utils/Pens";
import { fragWithHTML } from "src/utils/Utils";
import ExcalidrawView from "src/view/ExcalidrawView";
import ExcalidrawPlugin from "src/core/main";
import { setPen } from "src/view/components/menu/ObsidianMenu";
import { ExtendedFillStyle, PenType } from "src/types/penTypes";
import { getExcalidrawViews } from "src/utils/obsidianUtils";
import { PENS } from "src/utils/pens";
import { fragWithHTML } from "src/utils/utils";
import { __values } from "tslib";
const EASINGFUNCTIONS: Record<string,string> = {
@@ -53,7 +53,7 @@ export class PenSettingsModal extends Modal {
private view: ExcalidrawView,
private pen: number,
) {
super(app);
super(plugin.app);
this.api = view.excalidrawAPI;
}

View File

@@ -8,21 +8,20 @@ import {
TFile,
Notice,
TextAreaComponent,
TFolder,
} from "obsidian";
import ExcalidrawView from "../ExcalidrawView";
import ExcalidrawPlugin from "../main";
import { escapeRegExp, getLinkParts, sleep } from "../utils/Utils";
import { getLeaf, openLeaf } from "../utils/ObsidianUtils";
import { checkAndCreateFolder, splitFolderAndFilename } from "src/utils/FileUtils";
import { KeyEvent, isWinCTRLorMacCMD } from "src/utils/ModifierkeyHelper";
import ExcalidrawView from "../../view/ExcalidrawView";
import ExcalidrawPlugin from "../../core/main";
import { escapeRegExp, getLinkParts, sleep } from "../../utils/utils";
import { getLeaf, openLeaf } from "../../utils/obsidianUtils";
import { checkAndCreateFolder, splitFolderAndFilename } from "src/utils/fileUtils";
import { KeyEvent, isWinCTRLorMacCMD } from "src/utils/modifierkeyHelper";
import { t } from "src/lang/helpers";
import { ExcalidrawElement, getEA } from "src";
import { ExcalidrawAutomate } from "src/ExcalidrawAutomate";
import { ExcalidrawElement, getEA } from "src/core";
import { ExcalidrawAutomate } from "src/shared/ExcalidrawAutomate";
import { MAX_IMAGE_SIZE, REG_LINKINDEX_INVALIDCHARS } from "src/constants/constants";
import { REGEX_LINK, REGEX_TAGS } from "src/ExcalidrawData";
import { ScriptEngine } from "src/Scripts";
import { openExternalLink, openTagSearch, parseObsidianLink } from "src/utils/ExcalidrawViewUtils";
import { REGEX_LINK, REGEX_TAGS } from "../ExcalidrawData";
import { ScriptEngine } from "../Scripts";
import { openExternalLink, openTagSearch, parseObsidianLink } from "src/utils/excalidrawViewUtils";
export type ButtonDefinition = { caption: string; tooltip?:string; action: Function };

View File

@@ -1,7 +1,7 @@
import { Modal, Setting, TFile } from "obsidian";
import ExcalidrawPlugin from "src/main";
import { getIMGFilename } from "src/utils/FileUtils";
import { addIframe } from "src/utils/Utils";
import ExcalidrawPlugin from "src/core/main";
import { getIMGFilename } from "src/utils/fileUtils";
import { addIframe } from "src/utils/utils";
const haveLinkedFilesChanged = (depth: number, mtime: number, path: string, sourceList: Set<string>, plugin: ExcalidrawPlugin):boolean => {
if(depth++ > 5) return false;

View File

@@ -1,6 +1,6 @@
import { App, MarkdownRenderer, Modal } from "obsidian";
import ExcalidrawPlugin from "../main";
import { Rank, SwordColors } from "src/menu/ActionIcons";
import ExcalidrawPlugin from "../../core/main";
import { Rank, SwordColors } from "src/constants/actionIcons";
export class RankMessage extends Modal {

View File

@@ -1,6 +1,6 @@
import { App, MarkdownRenderer, Modal } from "obsidian";
import { isVersionNewerThanOther } from "src/utils/Utils";
import ExcalidrawPlugin from "../main";
import { isVersionNewerThanOther } from "src/utils/utils";
import ExcalidrawPlugin from "../../core/main";
import { FIRST_RUN, RELEASE_NOTES } from "./Messages";
declare const PLUGIN_VERSION:string;

View File

@@ -1,7 +1,7 @@
import { MarkdownRenderer, Modal, Notice, request } from "obsidian";
import ExcalidrawPlugin from "../main";
import { errorlog, escapeRegExp } from "../utils/Utils";
import { log } from "src/utils/DebugHelper";
import ExcalidrawPlugin from "../../core/main";
import { errorlog, escapeRegExp } from "../../utils/utils";
import { log } from "src/utils/debugHelper";
const URL =
"https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/index-new.md";

View File

@@ -1,10 +1,10 @@
import { App, FuzzySuggestModal, Notice, TFile } from "obsidian";
import { t } from "../lang/helpers";
import ExcalidrawView from "src/ExcalidrawView";
import { getEA } from "src";
import { ExcalidrawAutomate } from "src/ExcalidrawAutomate";
import { t } from "../../lang/helpers";
import ExcalidrawView from "src/view/ExcalidrawView";
import { getEA } from "src/core";
import { ExcalidrawAutomate } from "src/shared/ExcalidrawAutomate";
import { MD_EX_SECTIONS } from "src/constants/constants";
import { addBackOfTheNoteCard } from "src/utils/ExcalidrawViewUtils";
import { addBackOfTheNoteCard } from "src/utils/excalidrawViewUtils";
export class SelectCard extends FuzzySuggestModal<string> {

View File

@@ -1,15 +1,15 @@
import { ButtonComponent, DropdownComponent, TFile, ToggleComponent } from "obsidian";
import ExcalidrawView from "../ExcalidrawView";
import ExcalidrawPlugin from "../main";
import ExcalidrawView from "../../view/ExcalidrawView";
import ExcalidrawPlugin from "../../core/main";
import { Modal, Setting, TextComponent } from "obsidian";
import { FileSuggestionModal } from "../Components/Suggesters/FileSuggestionModal";
import { FileSuggestionModal } from "../Suggesters/FileSuggestionModal";
import { IMAGE_TYPES, sceneCoordsToViewportCoords, viewportCoordsToSceneCoords, MAX_IMAGE_SIZE, ANIMATED_IMAGE_TYPES, MD_EX_SECTIONS } from "src/constants/constants";
import { insertEmbeddableToView, insertImageToView } from "src/utils/ExcalidrawViewUtils";
import { getEA } from "src";
import { insertEmbeddableToView, insertImageToView } from "src/utils/excalidrawViewUtils";
import { getEA } from "src/core";
import { InsertPDFModal } from "./InsertPDFModal";
import { ExcalidrawImperativeAPI } from "@zsviczian/excalidraw/types/excalidraw/types";
import { ExcalidrawAutomate } from "src/ExcalidrawAutomate";
import { cleanSectionHeading } from "src/utils/ObsidianUtils";
import { ExcalidrawAutomate } from "src/shared/ExcalidrawAutomate";
import { cleanSectionHeading } from "src/utils/obsidianUtils";
export class UniversalInsertFileModal extends Modal {
private center: { x: number, y: number } = { x: 0, y: 0 };
@@ -176,7 +176,7 @@ export class UniversalInsertFileModal extends Modal {
button
.setButtonText("as Embeddable")
.onClick(async () => {
const path = app.metadataCache.fileToLinktext(
const path = this.app.metadataCache.fileToLinktext(
file,
this.view.file.path,
file.extension === "md",

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
import { DEVICE } from "src/constants/constants";
import ExcalidrawPlugin from "src/main";
import ExcalidrawPlugin from "src/core/main";
export class ExcalidrawConfig {
public areaLimit: number = 16777216;

View File

@@ -18,9 +18,9 @@ import {
refreshTextDimensions,
getContainerElement,
loadSceneFonts,
} from "./constants/constants";
import ExcalidrawPlugin from "./main";
import { TextMode } from "./ExcalidrawView";
} from "../constants/constants";
import ExcalidrawPlugin from "../core/main";
import { TextMode } from "../view/ExcalidrawView";
import {
addAppendUpdateCustomData,
compress,
@@ -37,8 +37,8 @@ import {
wrapTextAtCharLength,
arrayToMap,
compressAsync,
} from "./utils/Utils";
import { cleanBlockRef, cleanSectionHeading, getAttachmentsFolderAndFilePath, isObsidianThemeDark } from "./utils/ObsidianUtils";
} from "../utils/utils";
import { cleanBlockRef, cleanSectionHeading, getAttachmentsFolderAndFilePath, isObsidianThemeDark } from "../utils/obsidianUtils";
import {
ExcalidrawElement,
ExcalidrawImageElement,
@@ -47,15 +47,15 @@ import {
} from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { BinaryFiles, DataURL, SceneData } from "@zsviczian/excalidraw/types/excalidraw/types";
import { EmbeddedFile, MimeType } from "./EmbeddedFileLoader";
import { ConfirmationPrompt } from "./dialogs/Prompt";
import { getMermaidImageElements, getMermaidText, shouldRenderMermaid } from "./utils/MermaidUtils";
import { DEBUGGING, debug } from "./utils/DebugHelper";
import { ConfirmationPrompt } from "./Dialogs/Prompt";
import { getMermaidImageElements, getMermaidText, shouldRenderMermaid } from "../utils/mermaidUtils";
import { DEBUGGING, debug } from "../utils/debugHelper";
import { Mutable } from "@zsviczian/excalidraw/types/excalidraw/utility-types";
import { updateElementIdsInScene } from "./utils/ExcalidrawSceneUtils";
import { getNewUniqueFilepath } from "./utils/FileUtils";
import { t } from "./lang/helpers";
import { displayFontMessage } from "./utils/ExcalidrawViewUtils";
import { getPDFRect } from "./utils/PDFUtils";
import { updateElementIdsInScene } from "../utils/excalidrawSceneUtils";
import { getNewUniqueFilepath } from "../utils/fileUtils";
import { t } from "../lang/helpers";
import { displayFontMessage } from "../utils/excalidrawViewUtils";
import { getPDFRect } from "../utils/PDFUtils";
type SceneDataWithFiles = SceneData & { files: BinaryFiles };
@@ -518,7 +518,7 @@ export class ExcalidrawData {
return;
}
const saveVersion = this.scene.source.split("https://github.com/zsviczian/obsidian-excalidraw-plugin/releases/tag/")[1]??"1.8.16";
const saveVersion = this.scene.source?.split("https://github.com/zsviczian/obsidian-excalidraw-plugin/releases/tag/")[1]??"1.8.16";
const elements = this.scene.elements;
for (const el of elements) {
@@ -859,7 +859,7 @@ export class ExcalidrawData {
return true; //Text Elements header does not exist
}
data = data.slice(position);
const normalMatch = data.match(/^((%%\n*)?# Excalidraw Data\n## Text Elements(?:\n|$))/m)
const normalMatch = data.match(/^((%%\n*)?# Excalidraw Data\n\n?## Text Elements(?:\n|$))/m)
?? data.match(/^((%%\n*)?##? Text Elements(?:\n|$))/m);
const textElementsMatch = normalMatch
@@ -1427,7 +1427,7 @@ export class ExcalidrawData {
disableCompression: boolean = false;
generateMDBase(deletedElements: ExcalidrawElement[] = []) {
let outString = this.textElementCommentedOut ? "%%\n" : "";
outString += `# Excalidraw Data\n## Text Elements\n`;
outString += `# Excalidraw Data\n\n## Text Elements\n`;
if (this.plugin.settings.addDummyTextElement) {
outString += `\n^_dummy!_\n\n`;
}

View File

@@ -1,8 +1,8 @@
import { App, Notice, TFile } from "obsidian";
import ExcalidrawPlugin from "src/main";
import { convertSVGStringToElement } from "./Utils";
import { FILENAMEPARTS, PreviewImageType } from "./UtilTypes";
import { hasExcalidrawEmbeddedImagesTreeChanged } from "./FileUtils";
import ExcalidrawPlugin from "src/core/main";
import { convertSVGStringToElement } from "../utils/utils";
import { FILENAMEPARTS, PreviewImageType } from "../types/utilTypes";
import { hasExcalidrawEmbeddedImagesTreeChanged } from "../utils/fileUtils";
//@ts-ignore
const DB_NAME = "Excalidraw " + app.appId;

View File

@@ -1,6 +1,6 @@
// LaTeX.ts
import { DataURL } from "@zsviczian/excalidraw/types/excalidraw/types";
import ExcalidrawView from "./ExcalidrawView";
import ExcalidrawView from "../view/ExcalidrawView";
import { FileData, MimeType } from "./EmbeddedFileLoader";
import { FileId } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { App } from "obsidian";
@@ -33,7 +33,7 @@ export const updateEquation = async (
addFiles: Function,
) => {
await loadMathJax();
const data = await tex2dataURLExternal(equation, 4, app);
const data = await tex2dataURLExternal(equation, 4, view.app);
if (data) {
const files: FileData[] = [];
files.push({

View File

@@ -1,13 +1,13 @@
import { ExcalidrawAutomate } from "../ExcalidrawAutomate";
import {Notice, requestUrl} from "obsidian"
import ExcalidrawPlugin from "../main"
import ExcalidrawView, { ExportSettings } from "../ExcalidrawView"
import FrontmatterEditor from "src/utils/Frontmatter";
import ExcalidrawPlugin from "../../core/main"
import ExcalidrawView, { ExportSettings } from "../../view/ExcalidrawView"
import FrontmatterEditor from "src/shared/Frontmatter";
import { ExcalidrawElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { EmbeddedFilesLoader } from "src/EmbeddedFileLoader";
import { blobToBase64 } from "src/utils/FileUtils";
import { getEA } from "src";
import { log } from "src/utils/DebugHelper";
import { EmbeddedFilesLoader } from "../EmbeddedFileLoader";
import { blobToBase64 } from "src/utils/fileUtils";
import { getEA } from "src/core";
import { log } from "src/utils/debugHelper";
const TASKBONE_URL = "https://api.taskbone.com/"; //"https://excalidraw-preview.onrender.com/";
const TASKBONE_OCR_FN = "execute?id=60f394af-85f6-40bc-9613-5d26dc283cbb";

View File

@@ -4,18 +4,17 @@ import {
normalizePath,
TAbstractFile,
TFile,
WorkspaceLeaf,
} from "obsidian";
import { PLUGIN_ID } from "./constants/constants";
import ExcalidrawView from "./ExcalidrawView";
import ExcalidrawPlugin from "./main";
import { ButtonDefinition, GenericInputPrompt, GenericSuggester } from "./dialogs/Prompt";
import { getIMGFilename } from "./utils/FileUtils";
import { splitFolderAndFilename } from "./utils/FileUtils";
import { getEA } from "src";
import { ExcalidrawAutomate } from "./ExcalidrawAutomate";
import { WeakArray } from "./utils/WeakArray";
import { getExcalidrawViews } from "./utils/ObsidianUtils";
import { PLUGIN_ID } from "../constants/constants";
import ExcalidrawView from "../view/ExcalidrawView";
import ExcalidrawPlugin from "../core/main";
import { ButtonDefinition, GenericInputPrompt, GenericSuggester } from "./Dialogs/Prompt";
import { getIMGFilename } from "../utils/fileUtils";
import { splitFolderAndFilename } from "../utils/fileUtils";
import { getEA } from "src/core";
import { ExcalidrawAutomate } from "../shared/ExcalidrawAutomate";
import { WeakArray } from "./WeakArray";
import { getExcalidrawViews } from "../utils/obsidianUtils";
export type ScriptIconMap = {
[key: string]: { name: string; group: string; svgString: string };

View File

@@ -6,12 +6,12 @@ import {
EditorSuggestTriggerInfo,
TFile,
} from "obsidian";
import { FRONTMATTER_KEYS_INFO } from "../../dialogs/SuggesterInfo";
import { FRONTMATTER_KEYS_INFO } from "../Dialogs/SuggesterInfo";
import {
EXCALIDRAW_AUTOMATE_INFO,
EXCALIDRAW_SCRIPTENGINE_INFO,
} from "../../dialogs/SuggesterInfo";
import type ExcalidrawPlugin from "../../main";
} from "../Dialogs/SuggesterInfo";
import type ExcalidrawPlugin from "../../core/main";
/**
* The field suggester recommends document properties in source mode, ea and utils function and attribute names.

View File

@@ -9,7 +9,7 @@ import {
import { SuggestionModal } from "./SuggestionModal";
import { t } from "src/lang/helpers";
import { LinkSuggestion } from "src/types/types";
import ExcalidrawPlugin from "src/main";
import ExcalidrawPlugin from "src/core/main";
import { AUDIO_TYPES, CODE_TYPES, ICON_NAME, IMAGE_TYPES, VIDEO_TYPES } from "src/constants/constants";
export class FileSuggestionModal extends SuggestionModal<LinkSuggestion> {

View File

@@ -25,7 +25,7 @@ import {
import { getTransformMatrix, transformPoints } from "./transform";
import { pointsOnPath } from "points-on-path";
import { randomId, getWindingOrder } from "./utils";
import { ROUNDNESS } from "../constants/constants";
import { ROUNDNESS } from "../../constants/constants";
const SUPPORTED_TAGS = [
"svg",

View File

@@ -2,7 +2,7 @@ import { RestoredDataState } from "@zsviczian/excalidraw/types/excalidraw/data/r
import { ImportedDataState } from "@zsviczian/excalidraw/types/excalidraw/data/types";
import { BoundingBox } from "@zsviczian/excalidraw/types/excalidraw/element/bounds";
import { ElementsMap, ExcalidrawBindableElement, ExcalidrawElement, ExcalidrawFrameElement, ExcalidrawFrameLikeElement, ExcalidrawTextContainer, ExcalidrawTextElement, FontFamilyValues, FontString, NonDeleted, NonDeletedExcalidrawElement, Theme } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { FontMetadata } from "@zsviczian/excalidraw/types/excalidraw/fonts/metadata";
import { FontMetadata } from "@zsviczian/excalidraw/types/excalidraw/fonts/FontMetadata";
import { AppState, BinaryFiles, DataURL, GenerateDiagramToCode, Zoom } from "@zsviczian/excalidraw/types/excalidraw/types";
import { Mutable } from "@zsviczian/excalidraw/types/excalidraw/utility-types";
import { GlobalPoint } from "@zsviczian/excalidraw/types/math/types";
@@ -220,5 +220,6 @@ declare namespace ExcalidrawLib {
): string;
function safelyParseJSON (json: string): Record<string, any> | null;
function loadSceneFonts(elements: NonDeletedExcalidrawElement[]): Promise<void>;
function loadMermaid(): Promise<any>;
}

View File

@@ -0,0 +1,62 @@
// src/types/ExcalidrawViewTypes.ts
import { WorkspaceLeaf } from "obsidian";
import { FileId } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { ObsidianCanvasNode } from "../view/managers/CanvasNodeFactory";
export type Position = { x: number; y: number };
export interface SelectedElementWithLink {
id: string | null;
text: string | null;
}
export interface SelectedImage {
id: string | null;
fileId: FileId | null;
}
export interface EmbeddableLeafRef {
leaf: WorkspaceLeaf;
node?: ObsidianCanvasNode;
editNode?: Function;
}
export interface ViewSemaphores {
warnAboutLinearElementLinkClick: boolean;
//flag to prevent overwriting the changes the user makes in an embeddable view editing the back side of the drawing
embeddableIsEditingSelf: boolean;
popoutUnload: boolean; //the unloaded Excalidraw view was the last leaf in the popout window
viewunload: boolean;
//first time initialization of the view
scriptsReady: boolean;
//The role of justLoaded is to capture the Excalidraw.onChange event that fires right after the canvas was loaded for the first time to
//- prevent the first onChange event to mark the file as dirty and to consequently cause a save right after load, causing sync issues in turn
//- trigger autozoom (in conjunction with preventAutozoomOnLoad)
justLoaded: boolean;
//the modifyEventHandler in main.ts will fire when an Excalidraw file has changed (e.g. due to sync)
//when a drawing that is currently open in a view receives a sync update, excalidraw reload() is triggered
//the preventAutozoomOnLoad flag will prevent the open drawing from autozooming when it is reloaded
preventAutozoom: boolean;
autosaving: boolean; //flags that autosaving is in progress. Autosave is an async timer, the flag prevents collision with force save
forceSaving: boolean; //flags that forcesaving is in progress. The flag prevents collision with autosaving
dirty: string; //null if there are no changes to be saved, the path of the file if the drawing has unsaved changes
//reload() is triggered by modifyEventHandler in main.ts. preventReload is a one time flag to abort reloading
//to avoid interrupting the flow of drawing by the user.
preventReload: boolean;
isEditingText: boolean; //https://stackoverflow.com/questions/27132796/is-there-any-javascript-event-fired-when-the-on-screen-keyboard-on-mobile-safari
//Save is triggered by multiple threads when an Excalidraw pane is terminated
//- by the view itself
//- by the activeLeafChangeEventHandler change event handler
//- by monkeypatches on detach(next)
//This semaphore helps avoid collision of saves
saving: boolean;
hoverSleep: boolean; //flag with timer to prevent hover preview from being triggered dozens of times
wheelTimeout:number; //used to avoid hover preview while zooming
}

45
src/types/types.d.ts vendored
View File

@@ -1,6 +1,6 @@
import { TFile } from "obsidian";
import { ExcalidrawAutomate } from "../ExcalidrawAutomate";
import { ExcalidrawLib } from "../ExcalidrawLib";
import { ExcalidrawAutomate } from "../shared/ExcalidrawAutomate";
import { ExcalidrawLib } from "./excalidrawLib";
export type ConnectionPoint = "top" | "bottom" | "left" | "right" | null;
@@ -49,6 +49,9 @@ declare global {
ReactDOM?: any;
ExcalidrawLib?: any;
}
interface File {
path?: string;
}
}
declare module "obsidian" {
@@ -59,6 +62,24 @@ declare module "obsidian" {
metadataTypeManager: {
setType(name:string, type:string): void;
};
plugins: {
plugins: {
[key: string]: Plugin | undefined;
};
};
}
interface FileManager {
promptForFileRename(file: TFile): Promise<void>;
}
interface FileView {
_loaded: boolean;
headerEl: HTMLElement;
}
interface TextFileView {
lastSavedData: string;
}
interface Menu {
items: MenuItem[];
}
interface Keymap {
getRootScope(): Scope;
@@ -66,6 +87,16 @@ declare module "obsidian" {
interface Scope {
keys: any[];
}
interface WorkspaceLeaf {
id: string;
containerEl: HTMLDivElement;
tabHeaderInnerTitleEl: HTMLDivElement;
tabHeaderInnerIconEl: HTMLDivElement;
}
interface WorkspaceWindowInitData {
x?: number;
y?: number;
}
interface Workspace {
on(
name: "hover-link",
@@ -99,5 +130,15 @@ declare module "obsidian" {
interface MetadataCache {
getBacklinksForFile(file: TFile): any;
getLinks(): { [id: string]: Array<{ link: string; displayText: string; original: string; position: any }> };
getCachedFiles(): string[];
}
interface HoverPopover {
containerEl: HTMLElement;
hide(): void;
}
interface Plugin {
_loaded: boolean;
}
}

View File

@@ -1,6 +1,5 @@
import { DEVICE } from "../constants/constants";
import { Notice, RequestUrlResponse, requestUrl } from "obsidian";
import ExcalidrawPlugin from "src/main";
import ExcalidrawPlugin from "src/core/main";
type MessageContent =
| string

View File

@@ -1,6 +1,6 @@
import ExcalidrawPlugin from "src/main";
import { PromisePool, promiseTry } from "./Utils";
import { blobToBase64 } from "./FileUtils";
import ExcalidrawPlugin from "src/core/main";
import { PromisePool, promiseTry } from "./utils";
import { blobToBase64 } from "./fileUtils";
interface ExcalidrawFontFaceDescriptor {
uri: string;

View File

@@ -1,8 +1,8 @@
import { ExcalidrawEmbeddableElement, ExcalidrawFrameElement, ExcalidrawImageElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { Mutable } from "@zsviczian/excalidraw/types/excalidraw/utility-types";
import { getEA } from "src";
import { ExcalidrawAutomate } from "src/ExcalidrawAutomate";
import { getCropFileNameAndFolder, getListOfTemplateFiles, splitFolderAndFilename } from "./FileUtils";
import { getEA } from "src/core";
import { ExcalidrawAutomate } from "src/shared/ExcalidrawAutomate";
import { getCropFileNameAndFolder, getListOfTemplateFiles, splitFolderAndFilename } from "./fileUtils";
import { Notice, TFile } from "obsidian";
import { Radians } from "@zsviczian/excalidraw/types/math";

View File

@@ -1,9 +1,9 @@
import { NonDeletedExcalidrawElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { DEVICE, REG_LINKINDEX_INVALIDCHARS } from "src/constants/constants";
import { getParentOfClass } from "./ObsidianUtils";
import { getParentOfClass } from "./obsidianUtils";
import { TFile, WorkspaceLeaf } from "obsidian";
import { getLinkParts } from "./Utils";
import ExcalidrawView from "src/ExcalidrawView";
import { getLinkParts } from "./utils";
import ExcalidrawView from "src/view/ExcalidrawView";
export const useDefaultExcalidrawFrame = (element: NonDeletedExcalidrawElement) => {
return !(element.link.startsWith("[") || element.link.startsWith("file:") || element.link.startsWith("data:")); // && !element.link.match(TWITTER_REG);
@@ -37,7 +37,7 @@ export const processLinkText = (linkText: string, view:ExcalidrawView): { subpat
return {subpath, file: null};
}
const file = app.metadataCache.getFirstLinkpathDest(
const file = view.app.metadataCache.getFirstLinkpathDest(
linkText,
view.file.path,
);

View File

@@ -1,11 +1,11 @@
import { ExcalidrawImperativeAPI } from "@zsviczian/excalidraw/types/excalidraw/types";
import { ColorMaster } from "@zsviczian/colormaster";
import { ExcalidrawAutomate } from "src/ExcalidrawAutomate";
import ExcalidrawView from "src/ExcalidrawView";
import { ExcalidrawAutomate } from "src/shared/ExcalidrawAutomate";
import ExcalidrawView from "src/view/ExcalidrawView";
import { DynamicStyle } from "src/types/types";
import { cloneElement } from "src/ExcalidrawAutomate";
import { cloneElement } from "src/shared/ExcalidrawAutomate";
import { ExcalidrawFrameElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { addAppendUpdateCustomData } from "./Utils";
import { addAppendUpdateCustomData } from "./utils";
import { mutateElement } from "src/constants/constants";
export const setDynamicStyle = (

View File

@@ -1,15 +1,15 @@
import { MAX_IMAGE_SIZE, IMAGE_TYPES, ANIMATED_IMAGE_TYPES, MD_EX_SECTIONS } from "src/constants/constants";
import { App, Modal, Notice, TFile, WorkspaceLeaf } from "obsidian";
import { ExcalidrawAutomate } from "src/ExcalidrawAutomate";
import { REGEX_LINK, REG_LINKINDEX_HYPERLINK, getExcalidrawMarkdownHeaderSection, REGEX_TAGS } from "src/ExcalidrawData";
import ExcalidrawView from "src/ExcalidrawView";
import { ExcalidrawAutomate } from "src/shared/ExcalidrawAutomate";
import { REGEX_LINK, REG_LINKINDEX_HYPERLINK, getExcalidrawMarkdownHeaderSection, REGEX_TAGS } from "../shared/ExcalidrawData";
import ExcalidrawView from "src/view/ExcalidrawView";
import { ExcalidrawElement, ExcalidrawFrameElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { getEmbeddedFilenameParts, getLinkParts, isImagePartRef } from "./Utils";
import { cleanSectionHeading } from "./ObsidianUtils";
import { getEA } from "src";
import { getEmbeddedFilenameParts, getLinkParts, isImagePartRef } from "./utils";
import { cleanSectionHeading } from "./obsidianUtils";
import { getEA } from "src/core";
import { ExcalidrawImperativeAPI } from "@zsviczian/excalidraw/types/excalidraw/types";
import { EmbeddableMDCustomProps } from "src/dialogs/EmbeddableSettings";
import { EmbeddableMDCustomProps } from "src/shared/Dialogs/EmbeddableSettings";
import { nanoid } from "nanoid";
import { t } from "src/lang/helpers";

View File

@@ -1,12 +1,12 @@
import { DataURL } from "@zsviczian/excalidraw/types/excalidraw/types";
import { App, loadPdfJs, normalizePath, Notice, requestUrl, RequestUrlResponse, TAbstractFile, TFile, TFolder, Vault } from "obsidian";
import { DEVICE, FRONTMATTER_KEYS, URLFETCHTIMEOUT } from "src/constants/constants";
import { IMAGE_MIME_TYPES, MimeType } from "src/EmbeddedFileLoader";
import { ExcalidrawSettings } from "src/settings";
import { errorlog, getDataURL } from "./Utils";
import ExcalidrawPlugin from "src/main";
import { ANNOTATED_PREFIX, CROPPED_PREFIX } from "./CarveOut";
import { getAttachmentsFolderAndFilePath } from "./ObsidianUtils";
import { DEVICE, EXCALIDRAW_PLUGIN, FRONTMATTER_KEYS, URLFETCHTIMEOUT } from "src/constants/constants";
import { IMAGE_MIME_TYPES, MimeType } from "../shared/EmbeddedFileLoader";
import { ExcalidrawSettings } from "src/core/settings";
import { errorlog, getDataURL } from "./utils";
import ExcalidrawPlugin from "src/core/main";
import { ANNOTATED_PREFIX, CROPPED_PREFIX } from "./carveout";
import { getAttachmentsFolderAndFilePath } from "./obsidianUtils";
/**
* Splits a full path including a folderpath and a filename into separate folderpath and filename components
@@ -142,7 +142,7 @@ export function getEmbedFilename(
* @param folderpath
*/
export async function checkAndCreateFolder(folderpath: string):Promise<TFolder> {
const vault = app.vault;
const vault = EXCALIDRAW_PLUGIN.app.vault;
folderpath = normalizePath(folderpath);
//https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/658
//@ts-ignore
@@ -292,7 +292,7 @@ export const blobToBase64 = async (blob: Blob): Promise<string> => {
export const getPDFDoc = async (f: TFile): Promise<any> => {
if(typeof window.pdfjsLib === "undefined") await loadPdfJs();
return await window.pdfjsLib.getDocument(app.vault.getResourcePath(f)).promise;
return await window.pdfjsLib.getDocument(EXCALIDRAW_PLUGIN.app.vault.getResourcePath(f)).promise;
}
export const readLocalFile = async (filePath:string): Promise<string> => {
@@ -330,9 +330,14 @@ export const getPathWithoutExtension = (f:TFile): string => {
return f.path.substring(0, f.path.lastIndexOf("."));
}
const VAULT_BASE_URL = DEVICE.isDesktop
? app.vault.adapter.url.pathToFileURL(app.vault.adapter.basePath).toString()
let _VAULT_BASE_URL:string = null;
const VAULT_BASE_URL = () => {
if(_VAULT_BASE_URL) return _VAULT_BASE_URL;
_VAULT_BASE_URL = DEVICE.isDesktop
? EXCALIDRAW_PLUGIN.app.vault.adapter.url.pathToFileURL(EXCALIDRAW_PLUGIN.app.vault.adapter.basePath).toString()
: "";
return _VAULT_BASE_URL;
}
export const getInternalLinkOrFileURLLink = (
path: string, plugin:ExcalidrawPlugin, alias?: string, sourceFile?: TFile
@@ -344,8 +349,10 @@ export const getInternalLinkOrFileURLLink = (
}
const vault = plugin.app.vault;
const fileURLString = vault.adapter.url.pathToFileURL(path).toString();
if (fileURLString.startsWith(VAULT_BASE_URL)) {
const internalPath = normalizePath(unescape(fileURLString.substring(VAULT_BASE_URL.length)));
if (fileURLString.startsWith(VAULT_BASE_URL())) {
const internalPath = normalizePath(
decodeURIComponent(fileURLString.substring(VAULT_BASE_URL().length))
);
const file = vault.getAbstractFileByPath(internalPath);
if(file && file instanceof TFile) {
const link = plugin.app.metadataCache.fileToLinktext(

View File

@@ -1,8 +1,8 @@
import { ExcalidrawElement, ExcalidrawImageElement, ExcalidrawTextElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { REGEX_LINK, REG_LINKINDEX_HYPERLINK } from "src/ExcalidrawData";
import ExcalidrawView, { TextMode } from "src/ExcalidrawView";
import { rotatedDimensions } from "./Utils";
import { getBoundTextElementId } from "src/ExcalidrawAutomate";
import { REGEX_LINK, REG_LINKINDEX_HYPERLINK } from "../shared/ExcalidrawData";
import ExcalidrawView, { TextMode } from "src/view/ExcalidrawView";
import { rotatedDimensions } from "./utils";
import { getBoundTextElementId } from "src/shared/ExcalidrawAutomate";
export const getElementsAtPointer = (
pointer: any,

Some files were not shown because too many files have changed in this diff Show More