Compare commits

..

9 Commits

Author SHA1 Message Date
zsviczian
bb83523c0f fix script loading error 2024-11-04 12:29:20 +00:00
zsviczian
f83c0a8458 Merge pull request #2097 from dmscode/master
Update zh-cn.ts to 55ce645
2024-11-04 07:58:33 +01:00
dmscode
7411d51477 Update zh-cn.ts to 55ce645 2024-11-04 07:39:41 +08:00
zsviczian
55ce6456d8 2.6.4 2024-11-03 17:56:39 +01:00
zsviczian
da6619d55e 2.6.3 2024-11-03 15:07:11 +01:00
zsviczian
6033c057c2 2.6.3-beta-6 2024-11-03 13:32:18 +01:00
zsviczian
0efda1d6a6 2.6.3-beta-5 2024-11-03 00:54:38 +01:00
zsviczian
59107f0c2a 2.6.3-beta-4 2024-11-02 20:05:13 +01:00
zsviczian
f7cd05f6c4 2.6.3-beta-3 (refactored initiation) 2024-11-02 07:50:27 +01:00
13 changed files with 579 additions and 404 deletions

View File

@@ -1,7 +1,7 @@
{
"id": "obsidian-excalidraw-plugin",
"name": "Excalidraw",
"version": "2.6.3-beta-2",
"version": "2.6.4",
"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.2",
"version": "2.6.4",
"minAppVersion": "1.1.6",
"description": "An Obsidian plugin to edit and view Excalidraw drawings",
"author": "Zsolt Viczian",

View File

@@ -19,7 +19,7 @@
"license": "MIT",
"dependencies": {
"@popperjs/core": "^2.11.8",
"@zsviczian/excalidraw": "0.17.6-10",
"@zsviczian/excalidraw": "0.17.6-11",
"chroma-js": "^2.4.2",
"clsx": "^2.0.0",
"@zsviczian/colormaster": "^1.2.2",
@@ -38,6 +38,7 @@
"es6-promise-pool": "2.5.0"
},
"devDependencies": {
"jsesc": "^3.0.2",
"@babel/core": "^7.22.9",
"@babel/preset-env": "^7.22.10",
"@babel/preset-react": "^7.22.5",

View File

@@ -1,6 +1,7 @@
import { Extension } from "@codemirror/state";
import ExcalidrawPlugin from "src/main";
import { HideTextBetweenCommentsExtension } from "./Fadeout";
import { debug, DEBUGGING } from "src/utils/DebugHelper";
export const EDITOR_FADEOUT = "fadeOutExcalidrawMarkup";
const editorExtensions: {[key:string]:Extension}= {
@@ -10,13 +11,16 @@ const editorExtensions: {[key:string]:Extension}= {
export class EditorHandler {
private activeEditorExtensions: Extension[] = [];
constructor(private plugin: ExcalidrawPlugin) {}
constructor(private plugin: ExcalidrawPlugin) {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(EditorHandler, `ExcalidrawPlugin.construct EditorHandler`);
}
destroy(): void {
this.plugin = null;
}
setup(): void {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.setup, `ExcalidrawPlugin.construct EditorHandler.setup`);
this.plugin.registerEditorExtension(this.activeEditorExtensions);
this.updateCMExtensionState(EDITOR_FADEOUT, this.plugin.settings.fadeOutExcalidrawMarkup);
}

View File

@@ -2854,10 +2854,9 @@ export class ExcalidrawAutomate {
}
};
export async function initExcalidrawAutomate(
export function initExcalidrawAutomate(
plugin: ExcalidrawPlugin,
): Promise<ExcalidrawAutomate> {
await initFonts();
): ExcalidrawAutomate {
const ea = new ExcalidrawAutomate(plugin);
//@ts-ignore
window.ExcalidrawAutomate = ea;
@@ -2892,14 +2891,6 @@ function getFontFamily(id: number):string {
return getFontFamilyString({fontFamily:id})
}
export async function initFonts():Promise<void> {
/*await excalidrawLib.registerFontsInCSS();
const fonts = excalidrawLib.getFontFamilies();
for(let i=0;i<fonts.length;i++) {
if(fonts[i] !== "Local Font") await (document as any).fonts.load(`16px ${fonts[i]}`);
};*/
}
export function _measureText(
newText: string,
fontSize: number,

View File

@@ -1588,6 +1588,7 @@ export class ExcalidrawData {
.filter(el=>el.type === "image" && el.crop && !el.isDeleted)
.forEach((el: Mutable<ExcalidrawImageElement>)=>{
const ef = this.getFile(el.fileId);
if(!ef.file) return;
if(ef.file.extension !== "pdf") return;
const pageRef = ef.linkParts.original.split("#")?.[1];
if(!pageRef || !pageRef.startsWith("page=") || pageRef.includes("rect")) return;

View File

@@ -1,6 +1,7 @@
import {
App,
Instruction,
normalizePath,
TAbstractFile,
TFile,
WorkspaceLeaf,
@@ -22,6 +23,7 @@ export type ScriptIconMap = {
export class ScriptEngine {
private plugin: ExcalidrawPlugin;
private app: App;
private scriptPath: string;
//https://stackoverflow.com/questions/60218638/how-to-force-re-render-if-map-value-changes
public scriptIconMap: ScriptIconMap;
@@ -29,6 +31,7 @@ export class ScriptEngine {
constructor(plugin: ExcalidrawPlugin) {
this.plugin = plugin;
this.app = plugin.app;
this.scriptIconMap = {};
this.loadScripts();
this.registerEventHandlers();
@@ -58,7 +61,7 @@ export class ScriptEngine {
if (!path.endsWith(".svg")) {
return;
}
const scriptFile = app.vault.getAbstractFileByPath(
const scriptFile = this.app.vault.getAbstractFileByPath(
getIMGFilename(path, "md"),
);
if (scriptFile && scriptFile instanceof TFile) {
@@ -107,19 +110,19 @@ export class ScriptEngine {
registerEventHandlers() {
this.plugin.registerEvent(
this.plugin.app.vault.on(
this.app.vault.on(
"delete",
(file: TFile)=>this.deleteEventHandler(file)
),
);
this.plugin.registerEvent(
this.plugin.app.vault.on(
this.app.vault.on(
"create",
(file: TFile)=>this.createEventHandler(file)
),
);
this.plugin.registerEvent(
this.plugin.app.vault.on(
this.app.vault.on(
"rename",
(file: TAbstractFile, oldPath: string)=>this.renameEventHandler(file, oldPath)
),
@@ -138,15 +141,16 @@ export class ScriptEngine {
public getListofScripts(): TFile[] {
this.scriptPath = this.plugin.settings.scriptFolderPath;
if (!app.vault.getAbstractFileByPath(this.scriptPath)) {
//this.scriptPath = null;
if(!this.scriptPath) return;
this.scriptPath = normalizePath(this.scriptPath);
if (!this.app.vault.getAbstractFileByPath(this.scriptPath)) {
return;
}
return app.vault
return this.app.vault
.getFiles()
.filter(
(f: TFile) =>
f.path.startsWith(this.scriptPath) && f.extension === "md",
f.path.startsWith(this.scriptPath+"/") && f.extension === "md",
);
}
@@ -166,7 +170,10 @@ export class ScriptEngine {
}
const subpath = path.split(`${this.scriptPath}/`)[1];
const lastSlash = subpath.lastIndexOf("/");
if(!subpath) {
console.warn(`ScriptEngine.getScriptName unexpected basename: ${basename}; path: ${path}`)
}
const lastSlash = subpath?.lastIndexOf("/");
if (lastSlash > -1) {
return subpath.substring(0, lastSlash + 1) + basename;
}
@@ -175,10 +182,10 @@ export class ScriptEngine {
async addScriptIconToMap(scriptPath: string, name: string) {
const svgFilePath = getIMGFilename(scriptPath, "svg");
const file = app.vault.getAbstractFileByPath(svgFilePath);
const file = this.app.vault.getAbstractFileByPath(svgFilePath);
const svgString: string =
file && file instanceof TFile
? await app.vault.read(file)
? await this.app.vault.read(file)
: null;
this.scriptIconMap = {
...this.scriptIconMap,
@@ -199,12 +206,12 @@ export class ScriptEngine {
name: `(Script) ${scriptName}`,
checkCallback: (checking: boolean) => {
if (checking) {
return Boolean(app.workspace.getActiveViewOfType(ExcalidrawView));
return Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView));
}
const view = app.workspace.getActiveViewOfType(ExcalidrawView);
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
if (view) {
(async()=>{
const script = await app.vault.read(f);
const script = await this.app.vault.read(f);
if(script) {
//remove YAML frontmatter if present
this.executeScript(view, script, scriptName,f);
@@ -218,7 +225,7 @@ export class ScriptEngine {
}
unloadScripts() {
const scripts = app.vault
const scripts = this.app.vault
.getFiles()
.filter((f: TFile) => f.path.startsWith(this.scriptPath));
scripts.forEach((f) => {
@@ -236,11 +243,11 @@ export class ScriptEngine {
const commandId = `${PLUGIN_ID}:${basename}`;
// @ts-ignore
if (!this.plugin.app.commands.commands[commandId]) {
if (!this.app.commands.commands[commandId]) {
return;
}
// @ts-ignore
delete this.plugin.app.commands.commands[commandId];
delete this.app.commands.commands[commandId];
}
async executeScript(view: ExcalidrawView, script: string, title: string, file: TFile) {
@@ -271,7 +278,7 @@ export class ScriptEngine {
ScriptEngine.inputPrompt(
view,
this.plugin,
this.plugin.app,
this.app,
header,
placeholder,
value,
@@ -288,7 +295,7 @@ export class ScriptEngine {
instructions?: Instruction[],
) =>
ScriptEngine.suggester(
this.plugin.app,
this.app,
displayItems,
items,
hint,
@@ -304,7 +311,7 @@ export class ScriptEngine {
}
private updateToolPannels() {
const excalidrawViews = getExcalidrawViews(this.plugin.app);
const excalidrawViews = getExcalidrawViews(this.app);
excalidrawViews.forEach(excalidrawView => {
excalidrawView.toolsPanelRef?.current?.updateScriptIconMap(
this.scriptIconMap,

View File

@@ -17,6 +17,32 @@ 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.6.4":`
## Fixed
- Error saving when cropping images embedded from a URL (not from a file in the Vault) [#2096](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2096)
`,
"2.6.3":`
<div class="excalidraw-videoWrapper"><div>
<iframe src="https://www.youtube.com/embed/OfUWAvCgbXk" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</div></div>
## New
- **Cropping PDF Pages**
- Improved PDF++ cropping: You can now double-click cropped images in Excalidraw to adjust the crop area, which will also appear as a highlight in PDF++. This feature applies to PDF cut-outs created in version 2.6.3 and beyond.
- **Insert Last Active PDF Page as Image**
- New command palette action lets you insert the currently active PDF page into Excalidraw. Ideal for setups with PDF and Excalidraw side-by-side. You can assign a hotkey for quicker access. Cropped areas in Excalidraw will show as highlights in PDF++.
## Fixed
- Fixed **Close Settings** button toggle behavior [#2085](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2085)
- Resolved text wrapping issues causing layout shifts due to trailing whitespaces [#8714](https://github.com/excalidraw/excalidraw/pull/8714)
- **Aspect Ratio and Size Reset** commands now function correctly with cropped images.
- **Cropped Drawings**: Adjustments to cropped Excalidraw drawings are now supported. However, for nested Excalidraw drawings, it's recommended to use area, group, and frame references instead of cropping.
## Refactoring
- Further font loading optimizations on Excalidraw.com; no impact expected in Obsidian [#8693](https://github.com/excalidraw/excalidraw/pull/8693)
- Text wrapping improvements [#8715](https://github.com/excalidraw/excalidraw/pull/8715)
- Plugin initiation and error handling
`,
"2.6.2":`
## Fixed
- Image scaling issue with SVGs that miss the width and height property. [#8729](https://github.com/excalidraw/excalidraw/issues/8729)

View File

@@ -6,6 +6,8 @@ import { TAG_AUTOEXPORT, TAG_MDREADINGMODE, TAG_PDFEXPORT } from "src/constants/
import { labelALT, labelCTRL, labelMETA, labelSHIFT } from "src/utils/ModifierkeyHelper";
const CJK_FONTS = "CJK Fonts";
declare const PLUGIN_VERSION:string;
// English
export default {
// main.ts
@@ -959,4 +961,7 @@ FILENAME_HEAD: "Filename",
IPM_GROUP_PAGES_DESC: "This will group all pages into a single group. This is recommended if you are locking the pages after import, because the group will be easier to unlock later rather than unlocking one by one.",
IPM_SELECT_PDF: "Please select a PDF file",
//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",
};

View File

@@ -6,6 +6,8 @@ import { TAG_AUTOEXPORT, TAG_MDREADINGMODE, TAG_PDFEXPORT } from "src/constants/
import { labelALT, labelCTRL, labelMETA, labelSHIFT } from "src/utils/ModifierkeyHelper";
const CJK_FONTS = "CJK Fonts";
declare const PLUGIN_VERSION:string;
// 简体中文
export default {
// main.ts
@@ -870,6 +872,7 @@ FILENAME_HEAD: "文件名",
对此带来的不便,我深表歉意。
</p>
`,
//ObsidianMenu.tsx
GOTO_FULLSCREEN: "进入全屏模式",
EXIT_FULLSCREEN: "退出全屏模式",
@@ -958,4 +961,7 @@ FILENAME_HEAD: "文件名",
IPM_GROUP_PAGES_DESC: "这将把所有页面建立为一个单独的组。如果您在导入后锁定页面,建议使用此方法,因为这样可以更方便地解锁整个组,而不是逐个解锁。",
IPM_SELECT_PDF: "请选择一个 PDF 文件",
};
//Utils.ts
UPDATE_AVAILABLE: `Excalidraw 的新版本已在社区插件中可用。\n\n您正在使用 ${PLUGIN_VERSION}\n最新版本是`,
ERROR_PNG_TOO_LARGE: "导出 PNG 时出错 - PNG 文件过大,请尝试较小的分辨率",
};

View File

@@ -20,7 +20,6 @@ import {
Editor,
MarkdownFileInfo,
loadMermaid,
View,
} from "obsidian";
import {
BLANK_DRAWING,
@@ -146,6 +145,7 @@ import { WeakArray } from "./utils/WeakArray";
import { getCJKDataURLs } from "./utils/CJKLoader";
import { ExcalidrawLoading, switchToExcalidraw } from "./dialogs/ExcalidrawLoading";
import { insertImageToView } from "./utils/ExcalidrawViewUtils";
import tr from "./lang/locale/tr";
declare let EXCALIDRAW_PACKAGE:string;
declare let REACT_PACKAGES:string;
@@ -365,85 +365,221 @@ export default class ExcalidrawPlugin extends Plugin {
//Compatibility mode with .excalidraw files
this.registerExtensions(["excalidraw"], VIEW_TYPE_EXCALIDRAW);
await this.loadSettings({reEnableAutosave:true});
const updateSettings = !this.settings.onceOffCompressFlagReset || !this.settings.onceOffGPTVersionReset;
if(!this.settings.onceOffCompressFlagReset) {
this.settings.compress = true;
this.settings.onceOffCompressFlagReset = true;
}
if(!this.settings.onceOffGPTVersionReset) {
if(this.settings.openAIDefaultVisionModel === "gpt-4-vision-preview") {
this.settings.openAIDefaultVisionModel = "gpt-4o";
try {
await this.loadSettings({reEnableAutosave:true});
const updateSettings = !this.settings.onceOffCompressFlagReset || !this.settings.onceOffGPTVersionReset;
if(!this.settings.onceOffCompressFlagReset) {
this.settings.compress = true;
this.settings.onceOffCompressFlagReset = true;
}
if(!this.settings.onceOffGPTVersionReset) {
if(this.settings.openAIDefaultVisionModel === "gpt-4-vision-preview") {
this.settings.openAIDefaultVisionModel = "gpt-4o";
}
}
if(updateSettings) {
await this.saveSettings();
}
this.addSettingTab(new ExcalidrawSettingTab(this.app, this));
} catch (e) {
new Notice("Error loading plugin settings", 6000);
console.error("Error loading plugin settings", e);
}
try {
// need it her for ExcaliBrain
this.ea = initExcalidrawAutomate(this);
} catch (e) {
new Notice("Error initializing Excalidraw Automate", 6000);
console.error("Error initializing Excalidraw Automate", e);
}
try {
//Licat: Are you registering your post processors in onLayoutReady? You should register them in onload instead
this.addMarkdownPostProcessor();
} catch (e) {
new Notice("Error adding markdown post processor", 6000);
console.error("Error adding markdown post processor", e);
}
if(updateSettings) {
await this.saveSettings();
}
this.addSettingTab(new ExcalidrawSettingTab(this.app, this));
this.ea = await initExcalidrawAutomate(this);
this.addMarkdownPostProcessor();
this.app.workspace.onLayoutReady(async () => {
unpackExcalidraw();
excalidrawLib = window.eval.call(window,`(function() {${EXCALIDRAW_PACKAGE};return ExcalidrawLib;})()`);
this.packageMap.set(window,{react, reactDOM, excalidrawLib});
updateExcalidrawLib();
initCompressionWorker();
try {
unpackExcalidraw();
excalidrawLib = window.eval.call(window,`(function() {${EXCALIDRAW_PACKAGE};return ExcalidrawLib;})()`);
this.packageMap.set(window,{react, reactDOM, excalidrawLib});
updateExcalidrawLib();
} catch (e) {
new Notice("Error loading the Excalidraw package", 6000);
console.error("Error loading the Excalidraw package", e);
}
try {
initCompressionWorker();
} catch (e) {
new Notice("Error initializing compression worker", 6000);
console.error("Error initializing compression worker", e);
}
this.loadTimestamp = Date.now();
addIcon(ICON_NAME, EXCALIDRAW_ICON);
addIcon(SCRIPTENGINE_ICON_NAME, SCRIPTENGINE_ICON);
addIcon(EXPORT_IMG_ICON_NAME, EXPORT_IMG_ICON);
this.excalidrawConfig = new ExcalidrawConfig(this);
await loadMermaid();
this.editorHandler = new EditorHandler(this);
this.editorHandler.setup();
this.registerInstallCodeblockProcessor();
this.addThemeObserver();
this.experimentalFileTypeDisplayToggle(this.settings.experimentalFileType);
this.registerCommands();
this.registerEventListeners();
this.runStartupScript();
this.initializeFonts();
this.registerEditorSuggest(new FieldSuggester(this));
this.setPropertyTypes();
//inspiration taken from kanban:
//https://github.com/mgmeyers/obsidian-kanban/blob/44118e25661bff9ebfe54f71ae33805dc88ffa53/src/main.ts#L267
this.registerMonkeyPatches();
this.stylesManager = new StylesManager(this);
// const patches = new OneOffs(this);
if (this.settings.showReleaseNotes) {
//I am repurposing imageElementNotice, if the value is true, this means the plugin was just newly installed to Obsidian.
const obsidianJustInstalled = this.settings.previousRelease === "0.0.0"
if (isVersionNewerThanOther(PLUGIN_VERSION, this.settings.previousRelease)) {
new ReleaseNotes(
this.app,
this,
obsidianJustInstalled ? null : PLUGIN_VERSION,
).open();
}
try {
this.excalidrawConfig = new ExcalidrawConfig(this);
} catch (e) {
new Notice("Error initializing Excalidraw config", 6000);
console.error("Error initializing Excalidraw config", e);
}
this.switchToExcalidarwAfterLoad();
try {
await loadMermaid();
} catch (e) {
new Notice("Error loading Mermaid", 6000);
console.error("Error loading Mermaid", e);
}
this.taskbone = new Taskbone(this);
this.isReady = true;
switchToExcalidraw(this.app);
try {
this.addThemeObserver();
} catch (e) {
new Notice("Error adding theme observer", 6000);
console.error("Error adding theme observer", e);
}
this.app.workspace.onLayoutReady(() => {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.onload,"ExcalidrawPlugin.onload > app.workspace.onLayoutReady");
try {
//inspiration taken from kanban:
//https://github.com/mgmeyers/obsidian-kanban/blob/44118e25661bff9ebfe54f71ae33805dc88ffa53/src/main.ts#L267
this.registerMonkeyPatches();
} catch (e) {
new Notice("Error registering monkey patches", 6000);
console.error("Error registering monkey patches", e);
}
try {
this.stylesManager = new StylesManager(this);
} catch (e) {
new Notice("Error initializing styles manager", 6000);
console.error("Error initializing styles manager", e);
}
try {
this.scriptEngine = new ScriptEngine(this);
} catch (e) {
new Notice("Error initializing script engine", 6000);
console.error("Error initializing script engine", e);
}
try {
await this.initializeFonts();
} catch (e) {
new Notice("Error initializing fonts", 6000);
console.error("Error initializing fonts", e);
}
try {
imageCache.initializeDB(this);
});
} catch (e) {
new Notice("Error initializing image cache", 6000);
console.error("Error initializing image cache", e);
}
try {
this.isReady = true;
switchToExcalidraw(this.app);
this.switchToExcalidarwAfterLoad();
} catch (e) {
new Notice("Error switching views to Excalidraw", 6000);
console.error("Error switching views to Excalidraw", e);
}
try {
if (this.settings.showReleaseNotes) {
//I am repurposing imageElementNotice, if the value is true, this means the plugin was just newly installed to Obsidian.
const obsidianJustInstalled = (this.settings.previousRelease === "0.0.0") || !this.settings.previousRelease;
if (isVersionNewerThanOther(PLUGIN_VERSION, this.settings.previousRelease ?? "0.0.0")) {
new ReleaseNotes(
this.app,
this,
obsidianJustInstalled ? null : PLUGIN_VERSION,
).open();
}
}
} catch (e) {
new Notice("Error opening release notes", 6000);
console.error("Error opening release notes", e);
}
//---------------------------------------------------------------------
//initialization that can happen after Excalidraw views are initialized
//---------------------------------------------------------------------
try {
this.registerEventListeners();
} catch (e) {
new Notice("Error registering event listeners", 6000);
console.error("Error registering event listeners", e);
}
try {
this.runStartupScript();
} catch (e) {
new Notice("Error running startup script", 6000);
console.error("Error running startup script", e);
}
try {
this.editorHandler = new EditorHandler(this);
this.editorHandler.setup();
} catch (e) {
new Notice("Error setting up editor handler", 6000);
console.error("Error setting up editor handler", e);
}
try {
this.registerInstallCodeblockProcessor();
} catch (e) {
new Notice("Error registering script install-codeblock processor", 6000);
console.error("Error registering script install-codeblock processor", e);
}
try {
this.experimentalFileTypeDisplayToggle(this.settings.experimentalFileType);
} catch (e) {
new Notice("Error setting up experimental file type display", 6000);
console.error("Error setting up experimental file type display", e);
}
try {
this.registerCommands();
} catch (e) {
new Notice("Error registering commands", 6000);
console.error("Error registering commands", e);
}
try {
this.registerEditorSuggest(new FieldSuggester(this));
} catch (e) {
new Notice("Error registering editor suggester", 6000);
console.error("Error registering editor suggester", e);
}
try {
this.setPropertyTypes();
} catch (e) {
new Notice("Error setting up property types", 6000);
console.error("Error setting up property types", e);
}
try {
this.taskbone = new Taskbone(this);
} catch (e) {
new Notice("Error setting up taskbone", 6000);
console.error("Error setting up taskbone", e);
}
});
}
public async awaitInit() {
let counter = 0;
while(!this.isReady && counter < 150) {
@@ -451,78 +587,77 @@ export default class ExcalidrawPlugin extends Plugin {
}
}
private setPropertyTypes() {
/**
* Loads the Excalidraw frontmatter tags to Obsidian property suggester so people can more easily find relevant front matter switches
* Must run after the workspace is ready
* @returns
*/
private async setPropertyTypes() {
if(!this.settings.loadPropertySuggestions) return;
const app = this.app;
this.app.workspace.onLayoutReady(async () => {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.setPropertyTypes, `ExcalidrawPlugin.setPropertyTypes > app.workspace.onLayoutReady`);
await this.awaitInit();
Object.keys(FRONTMATTER_KEYS).forEach((key) => {
if(FRONTMATTER_KEYS[key].depricated === true) return;
const {name, type} = FRONTMATTER_KEYS[key];
app.metadataTypeManager.setType(name,type);
});
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.setPropertyTypes, `ExcalidrawPlugin.setPropertyTypes`);
Object.keys(FRONTMATTER_KEYS).forEach((key) => {
if(FRONTMATTER_KEYS[key].depricated === true) return;
const {name, type} = FRONTMATTER_KEYS[key];
app.metadataTypeManager.setType(name,type);
});
}
public initializeFonts() {
this.app.workspace.onLayoutReady(async () => {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.initializeFonts, `ExcalidrawPlugin.initializeFonts > app.workspace.onLayoutReady`);
await this.awaitInit();
const cjkFontDataURLs = await getCJKDataURLs(this);
if(typeof cjkFontDataURLs === "boolean" && !cjkFontDataURLs) {
new Notice(t("FONTS_LOAD_ERROR") + this.settings.fontAssetsPath,6000);
}
public async initializeFonts() {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.initializeFonts, `ExcalidrawPlugin.initializeFonts`);
const cjkFontDataURLs = await getCJKDataURLs(this);
if(typeof cjkFontDataURLs === "boolean" && !cjkFontDataURLs) {
new Notice(t("FONTS_LOAD_ERROR") + this.settings.fontAssetsPath,6000);
}
if(typeof cjkFontDataURLs === "object") {
const fontDeclarations = cjkFontDataURLs.map(dataURL =>
`@font-face { font-family: 'Xiaolai'; src: url("${dataURL}"); font-display: swap; font-weight: 400; }`
);
for(const ownerDocument of this.getOpenObsidianDocuments()) {
await this.addFonts(fontDeclarations, ownerDocument, CJK_STYLE_ID);
};
new Notice(t("FONTS_LOADED"));
}
const font = await getFontDataURL(
this.app,
this.settings.experimantalFourthFont,
"",
"Local Font",
if(typeof cjkFontDataURLs === "object") {
const fontDeclarations = cjkFontDataURLs.map(dataURL =>
`@font-face { font-family: 'Xiaolai'; src: url("${dataURL}"); font-display: swap; font-weight: 400; }`
);
if(font.dataURL === "") {
this.fourthFontLoaded = true;
return;
}
const fourthFontDataURL = font.dataURL;
const f = this.app.metadataCache.getFirstLinkpathDest(this.settings.experimantalFourthFont, "");
// Call getFontMetrics with the fourthFontDataURL
let fontMetrics = f.extension.startsWith("woff") ? undefined : await getFontMetrics(fourthFontDataURL, "Local Font");
if (!fontMetrics) {
console.log("Font Metrics not found, using default");
fontMetrics = {
unitsPerEm: 1000,
ascender: 750,
descender: -250,
lineHeight: 1.2,
fontName: "Local Font",
}
}
this.packageMap.forEach(({excalidrawLib}) => {
(excalidrawLib as typeof ExcalidrawLib).registerLocalFont({metrics: fontMetrics as any, icon: null}, fourthFontDataURL);
});
// Add fonts to open Obsidian documents
for(const ownerDocument of this.getOpenObsidianDocuments()) {
await this.addFonts([
`@font-face{font-family:'Local Font';src:url("${fourthFontDataURL}");font-display: swap;font-weight: 400;`,
], ownerDocument);
await this.addFonts(fontDeclarations, ownerDocument, CJK_STYLE_ID);
};
if(!this.fourthFontLoaded) setTimeout(()=>{this.fourthFontLoaded = true},100);
new Notice(t("FONTS_LOADED"));
}
const font = await getFontDataURL(
this.app,
this.settings.experimantalFourthFont,
"",
"Local Font",
);
if(font.dataURL === "") {
this.fourthFontLoaded = true;
return;
}
const fourthFontDataURL = font.dataURL;
const f = this.app.metadataCache.getFirstLinkpathDest(this.settings.experimantalFourthFont, "");
// Call getFontMetrics with the fourthFontDataURL
let fontMetrics = f.extension.startsWith("woff") ? undefined : await getFontMetrics(fourthFontDataURL, "Local Font");
if (!fontMetrics) {
console.log("Font Metrics not found, using default");
fontMetrics = {
unitsPerEm: 1000,
ascender: 750,
descender: -250,
lineHeight: 1.2,
fontName: "Local Font",
}
}
this.packageMap.forEach(({excalidrawLib}) => {
(excalidrawLib as typeof ExcalidrawLib).registerLocalFont({metrics: fontMetrics as any, icon: null}, fourthFontDataURL);
});
// Add fonts to open Obsidian documents
for(const ownerDocument of this.getOpenObsidianDocuments()) {
await this.addFonts([
`@font-face{font-family:'Local Font';src:url("${fourthFontDataURL}");font-display: swap;font-weight: 400;`,
], ownerDocument);
};
if(!this.fourthFontLoaded) setTimeout(()=>{this.fourthFontLoaded = true},100);
}
public async addFonts(declarations: string[],ownerDocument:Document = document, styleId:string = FONTS_STYLE_ID) {
@@ -563,23 +698,23 @@ export default class ExcalidrawPlugin extends Plugin {
return Array.from(visitedDocs);
}
/**
* Must be called after the workspace is ready
*/
private switchToExcalidarwAfterLoad() {
this.app.workspace.onLayoutReady(async () => {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.switchToExcalidarwAfterLoad, `ExcalidrawPlugin.switchToExcalidarwAfterLoad > app.workspace.onLayoutReady`);
await this.awaitInit();
let leaf: WorkspaceLeaf;
for (leaf of this.app.workspace.getLeavesOfType("markdown")) {
if ( leaf.view instanceof MarkdownView && this.isExcalidrawFile(leaf.view.file)) {
if (fileShouldDefaultAsExcalidraw(leaf.view.file?.path, this.app)) {
this.excalidrawFileModes[(leaf as any).id || leaf.view.file.path] =
VIEW_TYPE_EXCALIDRAW;
setExcalidrawView(leaf);
} else {
foldExcalidrawSection(leaf.view);
}
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.switchToExcalidarwAfterLoad, `ExcalidrawPlugin.switchToExcalidarwAfterLoad`);
let leaf: WorkspaceLeaf;
for (leaf of this.app.workspace.getLeavesOfType("markdown")) {
if ( leaf.view instanceof MarkdownView && this.isExcalidrawFile(leaf.view.file)) {
if (fileShouldDefaultAsExcalidraw(leaf.view.file?.path, this.app)) {
this.excalidrawFileModes[(leaf as any).id || leaf.view.file.path] =
VIEW_TYPE_EXCALIDRAW;
setExcalidrawView(leaf);
} else {
foldExcalidrawSection(leaf.view);
}
}
});
}
}
private forceSaveActiveView(checking:boolean):boolean {
@@ -877,8 +1012,10 @@ export default class ExcalidrawPlugin extends Plugin {
/**
* Display characters configured in settings, in front of the filename, if the markdown file is an excalidraw drawing
* Must be called after the workspace is ready
* The function is called from onload()
*/
private experimentalFileTypeDisplay() {
private async experimentalFileTypeDisplay() {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.experimentalFileTypeDisplay, `ExcalidrawPlugin.experimentalFileTypeDisplay`);
const insertFiletype = (el: HTMLElement) => {
if (el.childElementCount !== 1) {
@@ -920,18 +1057,15 @@ export default class ExcalidrawPlugin extends Plugin {
? new CustomMutationObserver(fileExplorerObserverFn, "fileExplorerObserver")
: new MutationObserver(fileExplorerObserverFn);
this.app.workspace.onLayoutReady(async () => {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.experimentalFileTypeDisplay, `ExcalidrawPlugin.experimentalFileTypeDisplay > app.workspace.onLayoutReady`);
await this.awaitInit();
document.querySelectorAll(".nav-file-title").forEach(insertFiletype); //apply filetype to files already displayed
const container = document.querySelector(".nav-files-container");
if (container) {
this.fileExplorerObserver.observe(container, {
childList: true,
subtree: true,
});
}
});
//the part that should only run after onLayoutReady
document.querySelectorAll(".nav-file-title").forEach(insertFiletype); //apply filetype to files already displayed
const container = document.querySelector(".nav-files-container");
if (container) {
this.fileExplorerObserver.observe(container, {
childList: true,
subtree: true,
});
}
}
private async actionRibbonClick(e: MouseEvent) {
@@ -2812,30 +2946,31 @@ export default class ExcalidrawPlugin extends Plugin {
);
}
private runStartupScript() {
/**
* Loads the startup script that will add event hooks to ExcalidrawAutomate (if provided by the user)
* Because of file operations, this must be run after the Obsidian Layout is ready
* @returns
*/
private async runStartupScript() {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.runStartupScript, `ExcalidrawPlugin.runStartupScript`);
if(!this.settings.startupScriptPath || this.settings.startupScriptPath === "") {
return;
}
this.app.workspace.onLayoutReady(async () => {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.runStartupScript, `ExcalidrawPlugin.runStartupScript > app.workspace.onLayoutReady, scriptPath:${this.settings?.startupScriptPath}`);
await this.awaitInit();
const path = this.settings.startupScriptPath.endsWith(".md")
? this.settings.startupScriptPath
: `${this.settings.startupScriptPath}.md`;
const f = this.app.vault.getAbstractFileByPath(path);
if (!f || !(f instanceof TFile)) {
new Notice(`Startup script not found: ${path}`);
return;
}
const script = await this.app.vault.read(f);
const AsyncFunction = Object.getPrototypeOf(async () => {}).constructor;
try {
await new AsyncFunction("ea", script)(this.ea);
} catch (e) {
new Notice(`Error running startup script: ${e}`);
}
});
const path = this.settings.startupScriptPath.endsWith(".md")
? this.settings.startupScriptPath
: `${this.settings.startupScriptPath}.md`;
const f = this.app.vault.getAbstractFileByPath(path);
if (!f || !(f instanceof TFile)) {
new Notice(`Startup script not found: ${path}`);
return;
}
const script = await this.app.vault.read(f);
const AsyncFunction = Object.getPrototypeOf(async () => {}).constructor;
try {
await new AsyncFunction("ea", script)(this.ea);
} catch (e) {
new Notice(`Error running startup script: ${e}`);
}
}
private lastPDFLeafID: string = null;
@@ -3001,204 +3136,209 @@ export default class ExcalidrawPlugin extends Plugin {
}
private popScope: Function = null;
private registerEventListeners() {
this.app.workspace.onLayoutReady(async () => {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.registerEventListeners,`ExcalidrawPlugin.registerEventListeners > app.workspace.onLayoutReady`);
await this.awaitInit();
const 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.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, {path}));
}
return;
}
if (element.type === "text") {
editorInsertText(editor, element.rawText);
return;
}
if (element.link) {
editorInsertText(editor, `${element.link}`);
return;
}
} catch (e) {
}
}
};
this.registerEvent(this.app.workspace.on("editor-paste", (evt, editor,info) => onPasteHandler(evt, editor, info)));
//watch filename change to rename .svg, .png; to sync to .md; to update links
const renameEventHandler = async (
file: TAbstractFile,
oldPath: string,
) => {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(renameEventHandler,`ExcalidrawPlugin.renameEventHandler`, file, oldPath);
if (!(file instanceof TFile)) {
return;
}
if (!this.isExcalidrawFile(file)) {
return;
}
if (!this.settings.keepInSync) {
return;
}
[EXPORT_TYPES, "excalidraw"].flat().forEach(async (ext: string) => {
const oldIMGpath = getIMGFilename(oldPath, ext);
const imgFile = app.vault.getAbstractFileByPath(
normalizePath(oldIMGpath),
);
if (imgFile && imgFile instanceof TFile) {
const newIMGpath = getIMGFilename(file.path, ext);
await this.app.fileManager.renameFile(imgFile, newIMGpath);
}
});
};
this.registerEvent(this.app.vault.on("rename", (file,oldPath) => renameEventHandler(file,oldPath)));
const modifyEventHandler = async (file: TFile) => {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(modifyEventHandler,`ExcalidrawPlugin.modifyEventHandler`, file);
const excalidrawViews = getExcalidrawViews(this.app);
excalidrawViews.forEach(async (excalidrawView) => {
if(excalidrawView.semaphores?.viewunload) {
/**
* Registers event listeners for the plugin
* Must be called after the workspace is read (onLayoutReady)
* Intended to be called from onLayoutReady in onload()
*/
private async registerEventListeners() {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.registerEventListeners,`ExcalidrawPlugin.registerEventListeners`);
await this.awaitInit();
const 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;
}
if (
excalidrawView.file &&
(excalidrawView.file.path === file.path ||
(file.extension === "excalidraw" &&
`${file.path.substring(
0,
file.path.lastIndexOf(".excalidraw"),
)}.md` === excalidrawView.file.path))
) {
if(excalidrawView.semaphores?.preventReload) {
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
if(excalidrawView.lastSaveTimestamp + 300000 < Date.now()) {
excalidrawView.reload(true, excalidrawView.file);
return;
}
if(file.extension==="md") {
if(excalidrawView.semaphores?.embeddableIsEditingSelf) return;
const inData = new ExcalidrawData(this);
const data = await this.app.vault.read(file);
await inData.loadData(data,file,getTextMode(data));
excalidrawView.synchronizeWithData(inData);
inData.destroy();
if(excalidrawView?.isDirty()) {
if(excalidrawView.autosaveTimer && excalidrawView.autosaveFunction) {
clearTimeout(excalidrawView.autosaveTimer);
}
if(excalidrawView.autosaveFunction) {
excalidrawView.autosaveFunction();
}
const element = hasOneTextElement
? drawing.elements.filter((el:ExcalidrawElement)=>el.type==="text")[0]
: drawing.elements[0];
if (element.type === "image") {
const fileinfo = this.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);
}
} else {
excalidrawView.reload(true, excalidrawView.file);
editorInsertText(editor, getLink(this, {path}));
}
return;
}
});
};
this.registerEvent(this.app.vault.on("modify", (file:TFile) => modifyEventHandler(file)));
//watch file delete and delete corresponding .svg and .png
const deleteEventHandler = async (file: TFile) => {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(deleteEventHandler,`ExcalidrawPlugin.deleteEventHandler`, file);
if (!(file instanceof TFile)) {
return;
}
const isExcalidarwFile = this.excalidrawFiles.has(file);
this.updateFileCache(file, undefined, true);
if (!isExcalidarwFile) {
return;
}
//close excalidraw view where this file is open
const excalidrawViews = getExcalidrawViews(this.app);
for (const excalidrawView of excalidrawViews) {
if (excalidrawView.file.path === file.path) {
await excalidrawView.leaf.setViewState({
type: VIEW_TYPE_EXCALIDRAW,
state: { file: null },
});
if (element.type === "text") {
editorInsertText(editor, element.rawText);
return;
}
if (element.link) {
editorInsertText(editor, `${element.link}`);
return;
}
} catch (e) {
}
}
};
this.registerEvent(this.app.workspace.on("editor-paste", (evt, editor,info) => onPasteHandler(evt, editor, info)));
//delete PNG and SVG files as well
if (this.settings.keepInSync) {
window.setTimeout(() => {
[EXPORT_TYPES, "excalidraw"].flat().forEach(async (ext: string) => {
const imgPath = getIMGFilename(file.path, ext);
const imgFile = this.app.vault.getAbstractFileByPath(
normalizePath(imgPath),
);
if (imgFile && imgFile instanceof TFile) {
await this.app.vault.delete(imgFile);
}
});
}, 500);
}
};
this.registerEvent(this.app.vault.on("delete", (file:TFile) => deleteEventHandler(file)));
//save Excalidraw leaf and update embeds when switching to another leaf
this.registerEvent(
this.app.workspace.on(
"active-leaf-change",
(leaf: WorkspaceLeaf) => this.activeLeafChangeEventHandler(leaf),
),
);
this.addFileSaveTriggerEventHandlers();
const metaCache: MetadataCache = this.app.metadataCache;
//@ts-ignore
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,
);
//watch filename change to rename .svg, .png; to sync to .md; to update links
const renameEventHandler = async (
file: TAbstractFile,
oldPath: string,
) => {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(renameEventHandler,`ExcalidrawPlugin.renameEventHandler`, file, oldPath);
if (!(file instanceof TFile)) {
return;
}
if (!this.isExcalidrawFile(file)) {
return;
}
if (!this.settings.keepInSync) {
return;
}
[EXPORT_TYPES, "excalidraw"].flat().forEach(async (ext: string) => {
const oldIMGpath = getIMGFilename(oldPath, ext);
const imgFile = app.vault.getAbstractFileByPath(
normalizePath(oldIMGpath),
);
if (imgFile && imgFile instanceof TFile) {
const newIMGpath = getIMGFilename(file.path, ext);
await this.app.fileManager.renameFile(imgFile, newIMGpath);
}
});
this.registerEvent(
metaCache.on("changed", (file, _, cache) =>
this.updateFileCache(file, cache?.frontmatter),
),
);
};
this.registerEvent(this.app.vault.on("rename", (file,oldPath) => renameEventHandler(file,oldPath)));
const modifyEventHandler = async (file: TFile) => {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(modifyEventHandler,`ExcalidrawPlugin.modifyEventHandler`, file);
const excalidrawViews = getExcalidrawViews(this.app);
excalidrawViews.forEach(async (excalidrawView) => {
if(excalidrawView.semaphores?.viewunload) {
return;
}
if (
excalidrawView.file &&
(excalidrawView.file.path === file.path ||
(file.extension === "excalidraw" &&
`${file.path.substring(
0,
file.path.lastIndexOf(".excalidraw"),
)}.md` === excalidrawView.file.path))
) {
if(excalidrawView.semaphores?.preventReload) {
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
if(excalidrawView.lastSaveTimestamp + 300000 < Date.now()) {
excalidrawView.reload(true, excalidrawView.file);
return;
}
if(file.extension==="md") {
if(excalidrawView.semaphores?.embeddableIsEditingSelf) return;
const inData = new ExcalidrawData(this);
const data = await this.app.vault.read(file);
await inData.loadData(data,file,getTextMode(data));
excalidrawView.synchronizeWithData(inData);
inData.destroy();
if(excalidrawView?.isDirty()) {
if(excalidrawView.autosaveTimer && excalidrawView.autosaveFunction) {
clearTimeout(excalidrawView.autosaveTimer);
}
if(excalidrawView.autosaveFunction) {
excalidrawView.autosaveFunction();
}
}
} else {
excalidrawView.reload(true, excalidrawView.file);
}
}
});
};
this.registerEvent(this.app.vault.on("modify", (file:TFile) => modifyEventHandler(file)));
//watch file delete and delete corresponding .svg and .png
const deleteEventHandler = async (file: TFile) => {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(deleteEventHandler,`ExcalidrawPlugin.deleteEventHandler`, file);
if (!(file instanceof TFile)) {
return;
}
const isExcalidarwFile = this.excalidrawFiles.has(file);
this.updateFileCache(file, undefined, true);
if (!isExcalidarwFile) {
return;
}
//close excalidraw view where this file is open
const excalidrawViews = getExcalidrawViews(this.app);
for (const excalidrawView of excalidrawViews) {
if (excalidrawView.file.path === file.path) {
await excalidrawView.leaf.setViewState({
type: VIEW_TYPE_EXCALIDRAW,
state: { file: null },
});
}
}
//delete PNG and SVG files as well
if (this.settings.keepInSync) {
window.setTimeout(() => {
[EXPORT_TYPES, "excalidraw"].flat().forEach(async (ext: string) => {
const imgPath = getIMGFilename(file.path, ext);
const imgFile = this.app.vault.getAbstractFileByPath(
normalizePath(imgPath),
);
if (imgFile && imgFile instanceof TFile) {
await this.app.vault.delete(imgFile);
}
});
}, 500);
}
};
this.registerEvent(this.app.vault.on("delete", (file:TFile) => deleteEventHandler(file)));
//save Excalidraw leaf and update embeds when switching to another leaf
this.registerEvent(
this.app.workspace.on(
"active-leaf-change",
(leaf: WorkspaceLeaf) => this.activeLeafChangeEventHandler(leaf),
),
);
this.addFileSaveTriggerEventHandlers();
const metaCache: MetadataCache = this.app.metadataCache;
//@ts-ignore
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,
);
}
});
this.registerEvent(
metaCache.on("changed", (file, _, cache) =>
this.updateFileCache(file, cache?.frontmatter),
),
);
}
//Save the drawing if the user clicks outside the canvas

View File

@@ -31,6 +31,7 @@ import opentype from 'opentype.js';
import { runCompressionWorker } from "src/workers/compression-worker";
import Pool from "es6-promise-pool";
import { FileData } from "src/EmbeddedFileLoader";
import { t } from "src/lang/helpers";
declare const PLUGIN_VERSION:string;
declare var LZString: any;
@@ -77,7 +78,7 @@ export async function checkExcalidrawVersion() {
if (isVersionNewerThanOther(latestVersion,PLUGIN_VERSION)) {
new Notice(
`A newer version of Excalidraw is available in Community Plugins.\n\nYou are using ${PLUGIN_VERSION}.\nThe latest is ${latestVersion}`,
t("UPDATE_AVAILABLE") + ` ${latestVersion}`,
);
}
} catch (e) {
@@ -220,15 +221,6 @@ export async function getFontDataURL (
const split = dataURL.split(";base64,", 2);
dataURL = `${split[0]};charset=utf-8;base64,${split[1]}`;
fontDef = ` @font-face {font-family: "${fontName}";src: url("${dataURL}") format("${format}")}`;
/* const mimeType = f.extension.startsWith("woff")
? "application/font-woff"
: "font/truetype";
fontName = name ?? f.basename;
dataURL = await getDataURL(ab, mimeType);
fontDef = ` @font-face {font-family: "${fontName}";src: url("${dataURL}")}`;
//format("${f.extension === "ttf" ? "truetype" : f.extension}");}`;
const split = fontDef.split(";base64,", 2);
fontDef = `${split[0]};charset=utf-8;base64,${split[1]}`;*/
}
return { fontDef, fontName, dataURL };
};
@@ -375,7 +367,7 @@ export async function getPNG (
}),
});
} catch (error) {
new Notice("Error exporting PNG - PNG too large, try a smaller resolution");
new Notice(t("ERROR_PNG_TOO_LARGE"));
errorlog({ where: "Utils.getPNG", error });
return null;
}
@@ -773,6 +765,8 @@ export function getPNGScale (plugin: ExcalidrawPlugin, file: TFile): number {
};
export function isVersionNewerThanOther (version: string, otherVersion: string): boolean {
if(!version || !otherVersion) return true;
const v = version.match(/(\d*)\.(\d*)\.(\d*)/);
const o = otherVersion.match(/(\d*)\.(\d*)\.(\d*)/);

View File

@@ -346,7 +346,7 @@ label.color-input-container > input {
padding: 0;
}
.excalidraw-settings input:not([type="color"]) {
.excalidraw-settings input[type="text"] {
min-width: 10em;
}