Compare commits

..

8 Commits
1.7.1 ... 1.7.5

Author SHA1 Message Date
Zsolt Viczian
ea39b8c6a1 1.7.5 2022-07-02 17:54:27 +02:00
Zsolt Viczian
e5fb705f0b 7.1.5 - embedding fixes 2022-07-02 14:07:43 +02:00
Zsolt Viczian
8046b5dc1f 1.7.4 2022-07-01 17:58:43 +02:00
Zsolt Viczian
08e4e1f131 1.7.3 beta release 2022-06-24 10:16:38 +02:00
Zsolt Viczian
108293ae5c minor cleanup 2022-06-23 18:16:27 +02:00
Zsolt Viczian
73528596d2 1.7.2 2022-06-23 07:19:17 +02:00
Zsolt Viczian
d2284b8d14 1.7.2 WIP 2022-06-22 23:50:19 +02:00
Zsolt Viczian
7cd3ec40c6 replaced activeLeaf, added openInPopout 2022-06-22 19:59:03 +02:00
23 changed files with 1055 additions and 877 deletions

View File

@@ -1,8 +1,8 @@
{
"id": "obsidian-excalidraw-plugin",
"name": "Excalidraw",
"version": "1.7.1",
"minAppVersion": "0.15.2",
"version": "1.7.5",
"minAppVersion": "0.15.3",
"description": "An Obsidian plugin to edit and view Excalidraw drawings",
"author": "Zsolt Viczian",
"authorUrl": "https://zsolt.blog",

View File

@@ -18,22 +18,22 @@
"license": "MIT",
"dependencies": {
"@types/lz-string": "^1.3.34",
"@zsviczian/excalidraw": "0.11.0-obsidian-21-namedexport",
"clsx": "1.1.1",
"@zsviczian/excalidraw": "0.11.0-obsidian-24",
"clsx": "^1.1.1",
"lz-string": "^1.4.4",
"monkey-around": "^2.3.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "^5.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "^5.0.1",
"roughjs": "^4.5.2"
},
"devDependencies": {
"@babel/core": "^7.16.12",
"@babel/preset-env": "^7.16.11",
"@babel/preset-react": "^7.16.7",
"@babel/preset-react": "^7.18.6",
"@excalidraw/eslint-config": "1.0.0",
"@excalidraw/prettier-config": "1.0.2",
"@popperjs/core": "^2.11.2",
"@popperjs/core": "^2.11.5",
"@rollup/plugin-babel": "^5.3.0",
"@rollup/plugin-commonjs": "^21.0.1",
"@rollup/plugin-node-resolve": "^13.1.3",
@@ -41,13 +41,13 @@
"@rollup/plugin-typescript": "^8.3.0",
"@types/js-beautify": "^1.13.3",
"@types/node": "^15.12.4",
"@types/react-dom": "^17.0.11",
"@types/react-dom": "^18.0.5",
"@zerollup/ts-transform-paths": "^1.7.18",
"cross-env": "^7.0.3",
"eslint-config-prettier": "8.3.0",
"eslint-plugin-prettier": "^4.0.0",
"html2canvas": "^1.4.0",
"nanoid": "^3.1.31",
"nanoid": "^4.0.0",
"obsidian": "^0.15.1",
"prettier": "^2.5.1",
"rollup": "^2.70.1",

View File

@@ -14,7 +14,6 @@ import LZString from 'lz-string';
import postprocess from 'rollup-plugin-postprocess';
const isProd = (process.env.NODE_ENV === "production");
console.log("Is production", isProd);
const excalidraw_pkg = isProd
? fs.readFileSync("./node_modules/@zsviczian/excalidraw/dist/excalidraw.production.min.js", "utf8")
@@ -25,15 +24,19 @@ const react_pkg = isProd
const reactdom_pkg = 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");
const lzstring_pkg = fs.readFileSync("./node_modules/lz-string/libs/lz-string.min.js", "utf8")
const lzstring_pkg = fs.readFileSync("./node_modules/lz-string/libs/lz-string.min.js", "utf8");
const manifestStr = fs.readFileSync("manifest.json", "utf-8");
const manifest = JSON.parse(manifestStr);
console.log(manifest.version);
const packageString = ';'+lzstring_pkg+'const EXCALIDRAW_PACKAGES = "' + LZString.compressToBase64(react_pkg + reactdom_pkg + excalidraw_pkg) + '";' +
'const {react, reactDOM, excalidrawLib} = window.eval.call(window, `(function() {' +
'${LZString.decompressFromBase64(EXCALIDRAW_PACKAGES)};' +
'return {react:React, reactDOM:ReactDOM, excalidrawLib: ExcalidrawLib};})();`);' +
'const PLUGIN_VERSION="'+manifest.version+'";';
const packageString = ';'+lzstring_pkg+'const EXCALIDRAW_PACKAGES = "' + LZString.compressToBase64(react_pkg + reactdom_pkg + excalidraw_pkg) +'";var ExcalidrawPackageLoader=(d=document)=>{if(!d.getElementById("excalidraw-script")){const script=d.createElement("script");script.type="text/javascript";script.id="excalidraw-script";script.text=LZString.decompressFromBase64(EXCALIDRAW_PACKAGES);d.body.appendChild(script);}};ExcalidrawPackageLoader();';
/*fs.writeFileSync("packageloader.js",packageString,{
encoding: "utf8",
flag: "w",
mode: 0o666
});*/
const BASE_CONFIG = {
input: 'src/main.ts',
@@ -67,15 +70,17 @@ const BUILD_CONFIG = {
commonjs(),
nodeResolve({ browser: true, preferBuiltins: false }),
typescript({inlineSources: !isProd}),
...isProd ? [
...isProd
? [
terser({toplevel: false, compress: {passes: 2}}),
//!postprocess:
//!postprocess - the version available on npmjs does not work, need this update:
// npm install brettz9/rollup-plugin-postprocess#update --save-dev
// https://github.com/developit/rollup-plugin-postprocess/issues/10
postprocess([
[/,React=require\("react"\);/, packageString],
])
] : [
]
: [
postprocess([
[/var React = require\('react'\);/, packageString],
])

View File

@@ -40,18 +40,16 @@ import { t } from "./lang/helpers";
import { ScriptEngine } from "./Scripts";
import { ConnectionPoint, ExcalidrawAutomateInterface } from "./types";
declare global {
interface Window {
ExcalidrawLib: any;
}
}
declare const PLUGIN_VERSION:string;
const {
determineFocusDistance,
intersectElementWithLine,
getCommonBoundingBox,
getMaximumGroups,
measureText,
} = window.ExcalidrawLib;
//@ts-ignore
} = excalidrawLib;
const GAP = 4;
@@ -361,7 +359,7 @@ export class ExcalidrawAutomate implements ExcalidrawAutomateInterface {
params?.filename
? params.filename + (params.filename.endsWith(".md") ? "": ".excalidraw.md")
: getDrawingFilename(this.plugin.settings),
params?.onNewPane ? params.onNewPane : false,
(params?.onNewPane ? params.onNewPane : false)?"new-pane":"active-pane",
params?.foldername ? params.foldername : this.plugin.settings.folder,
this.plugin.settings.compatibilityMode
? JSON.stringify(scene, null, "\t")
@@ -1141,7 +1139,7 @@ export class ExcalidrawAutomate implements ExcalidrawAutomateInterface {
*/
setView(view: ExcalidrawView | "first" | "active"): ExcalidrawView {
if (view == "active") {
const v = this.plugin.app.workspace.activeLeaf.view;
const v = this.plugin.app.workspace.getActiveViewOfType(ExcalidrawView);
if (!(v instanceof ExcalidrawView)) {
return;
}
@@ -1622,9 +1620,7 @@ export class ExcalidrawAutomate implements ExcalidrawAutomateInterface {
* @returns
*/
verifyMinimumPluginVersion(requiredVersion: string): boolean {
//@ts-ignore
const manifest = this.plugin.app.plugins.manifests[PLUGIN_ID];
return manifest.version >= requiredVersion;
return PLUGIN_VERSION >= requiredVersion;
};
/**

View File

@@ -1039,10 +1039,12 @@ export class ExcalidrawData {
const processedIds = new Set<string>();
fileIds.forEach(fileId=>{
if(processedIds.has(fileId)) {
const file = this.files.get(fileId as FileId);
const equation = this.equations.get(fileId as FileId);
const file = this.getFile(fileId);
//const file = this.files.get(fileId as FileId);
const equation = this.getEquation(fileId);
//const equation = this.equations.get(fileId as FileId);
//images should have a single reference, but equations and markdown embeds should have as many as instances of the file in the scene
if(file && file.file.extension !== "md") {
if(file && (file.file.extension !== "md" || !this.plugin.isExcalidrawFile(file.file))) {
return;
}
const newId = fileid();
@@ -1051,10 +1053,12 @@ export class ExcalidrawData {
dirty = true;
processedIds.add(newId);
if(file) {
this.files.set(newId as FileId,new EmbeddedFile(this.plugin,this.file.path,file.linkParts.original))
this.setFile(newId as FileId,new EmbeddedFile(this.plugin,this.file.path,file.linkParts.original));
//this.files.set(newId as FileId,new EmbeddedFile(this.plugin,this.file.path,file.linkParts.original))
}
if(equation) {
this.equations.set(newId as FileId, equation);
this.setEquation(newId as FileId, {latex:equation.latex, isLoaded:false});
//this.equations.set(newId as FileId, equation);
}
}
processedIds.add(fileId);
@@ -1350,8 +1354,13 @@ export class ExcalidrawData {
if (!data.file) {
return;
}
const parts = data.linkParts.original.split("#");
this.plugin.filesMaster.set(fileId, {
path: data.file.path,
path:data.file.path,
blockrefData: parts.length === 1
? null
: parts[1],
hasSVGwithBitmap: data.isSVGwithBitmap,
});
}
@@ -1361,7 +1370,19 @@ export class ExcalidrawData {
}
public getFile(fileId: FileId): EmbeddedFile {
return this.files.get(fileId);
let embeddedFile = this.files.get(fileId);
if(embeddedFile) return embeddedFile;
const masterFile = this.plugin.filesMaster.get(fileId);
if(!masterFile) return embeddedFile;
embeddedFile = new EmbeddedFile(
this.plugin,
this.file.path,
masterFile.blockrefData
? masterFile.path + "#" + masterFile.blockrefData
: masterFile.path
);
this.files.set(fileId,embeddedFile);
return embeddedFile;
}
public getFileEntries() {
@@ -1380,15 +1401,17 @@ export class ExcalidrawData {
return true;
}
if (this.plugin.filesMaster.has(fileId)) {
const fileMaster = this.plugin.filesMaster.get(fileId);
if (!this.app.vault.getAbstractFileByPath(fileMaster.path)) {
const masterFile = this.plugin.filesMaster.get(fileId);
if (!this.app.vault.getAbstractFileByPath(masterFile.path)) {
this.plugin.filesMaster.delete(fileId);
return true;
} // the file no longer exists
const embeddedFile = new EmbeddedFile(
this.plugin,
this.file.path,
fileMaster.path,
masterFile.blockrefData
? masterFile.path + "#" + masterFile.blockrefData
: masterFile.path
);
this.files.set(fileId, embeddedFile);
return true;
@@ -1405,7 +1428,12 @@ export class ExcalidrawData {
}
public getEquation(fileId: FileId): { latex: string; isLoaded: boolean } {
return this.equations.get(fileId);
let result = this.equations.get(fileId);
if(result) return result;
const latex = this.plugin.equationsMaster.get(fileId);
if(!latex) return result;
this.equations.set(fileId, {latex, isLoaded: false});
return {latex, isLoaded: false};
}
public getEquationEntries() {
@@ -1514,6 +1542,7 @@ export const getTransclusion = async (
const c = headings[i].node.children[0];
const dataHeading = headings[i].node.data?.hProperties?.dataHeading;
const cc = c?.children;
//const refNoSpace = linkParts.ref.replaceAll(" ","");
if (
!startPos &&
(c?.value?.replaceAll(REG_BLOCK_REF_CLEAN, "") === linkParts.ref ||

View File

@@ -56,8 +56,7 @@ import {
} from "./utils/FileUtils";
import {
checkExcalidrawVersion,
decompress,
//debug,
debug,
embedFontsInSVG,
errorlog,
getExportTheme,
@@ -88,13 +87,6 @@ import { ToolsPanel } from "./menu/ToolsPanel";
import { ScriptEngine } from "./Scripts";
import { getTextElementAtPointer, getImageElementAtPointer, getElementWithLinkAtPointer } from "./utils/GetElementAtPointer";
declare global {
interface Window {
ExcalidrawLib: any;
React: any;
ReactDOM: any;
}
}
export enum TextMode {
parsed,
@@ -449,10 +441,11 @@ export default class ExcalidrawView extends TextFileView {
}
try {
const allowSave =
const allowSave = Boolean (
(this.semaphores.dirty !== null && this.semaphores.dirty) ||
this.semaphores.autosaving ||
forcesave; //dirty == false when view.file == null;
forcesave
); //dirty == false when view.file == null;
const scene = this.getScene();
if (this.compatibilityMode) {
@@ -796,7 +789,7 @@ export default class ExcalidrawView extends TextFileView {
addFiles,
this.plugin,
);
this.setDirty();
this.setDirty(1);
});
return;
}
@@ -822,7 +815,7 @@ export default class ExcalidrawView extends TextFileView {
ef.resetImage(this.file.path, link);
await this.save(false);
await this.loadSceneFiles();
this.setDirty();
this.setDirty(2);
});
return;
}
@@ -895,15 +888,24 @@ export default class ExcalidrawView extends TextFileView {
diskIcon: HTMLElement;
excalidrawGetSceneVersion: (elements: ExcalidrawElement[]) => number;
getSceneVersion (elements: ExcalidrawElement[]):number {
if(!this.excalidrawGetSceneVersion) {
this.excalidrawGetSceneVersion = this.plugin.getPackage(this.ownerWindow).excalidrawLib.getSceneVersion;
}
return this.excalidrawGetSceneVersion(elements.filter(el=>!el.isDeleted));
}
onload() {
app.workspace.onLayoutReady(()=>{
const doc = app.isMobile?document:this.containerEl.ownerDocument;
this.ownerDocument = doc;
this.ownerWindow = this.ownerDocument.defaultView;
//@ts-ignore
ExcalidrawPackageLoader(doc); //function added during build in rollup
this.semaphores.scriptsReady = true;
});
const apiMissing = Boolean(typeof this.containerEl.onWindowMigrated === "undefined")
//@ts-ignore
if(!app.isMobile && !apiMissing) this.containerEl.onWindowMigrated(()=>this.leaf.rebuildView());
const doc = app.isMobile?document:this.containerEl.ownerDocument;
this.ownerDocument = doc;
this.ownerWindow = this.ownerDocument.defaultView;
this.plugin.getPackage(this.ownerWindow);
this.semaphores.scriptsReady = true;
this.addAction(SCRIPTENGINE_ICON_NAME, t("INSTALL_SCRIPT_BUTTON"), () => {
new ScriptInstallPrompt(this.plugin).open();
});
@@ -995,7 +997,7 @@ export default class ExcalidrawView extends TextFileView {
if (this.slidingPanesListner) {
(
this.app.workspace.rootSplit as WorkspaceItem as WorkspaceItemExt
).containerEl.removeEventListener("scroll", this.slidingPanesListner);
).containerEl?.removeEventListener("scroll", this.slidingPanesListner);
}
}
@@ -1150,8 +1152,8 @@ export default class ExcalidrawView extends TextFileView {
//save current drawing when user closes workspace leaf
onunload() {
this.semaphores.viewunload = true;
this.ownerWindow.removeEventListener("keydown", this.onKeyDown, false);
this.ownerWindow.removeEventListener("keyup", this.onKeyUp, false);
this.ownerWindow?.removeEventListener("keydown", this.onKeyDown, false);
this.ownerWindow?.removeEventListener("keyup", this.onKeyUp, false);
if(this.getHookServer().onViewUnloadHook) {
try {
@@ -1160,11 +1162,11 @@ export default class ExcalidrawView extends TextFileView {
errorlog({where: "ExcalidrawView.onunload", fn: this.getHookServer().onViewUnloadHook, error: e});
}
}
const tooltip = this.ownerDocument.body.querySelector(
const tooltip = this.containerEl?.ownerDocument?.body.querySelector(
"body>div.excalidraw-tooltip,div.excalidraw-tooltip--visible",
);
if (tooltip) {
this.ownerDocument.body.removeChild(tooltip);
this.containerEl?.ownerDocument?.body.removeChild(tooltip);
}
this.removeParentMoveObserver();
this.removeSlidingPanesListner();
@@ -1537,12 +1539,11 @@ export default class ExcalidrawView extends TextFileView {
}
}
})
const getSceneVersion = this.ownerWindow.ExcalidrawLib.getSceneVersion;
this.previousSceneVersion = getSceneVersion(sceneElements);
this.previousSceneVersion = this.getSceneVersion(sceneElements);
//changing files could result in a race condition for sync. If at the end of sync there are differences
//set dirty will trigger an autosave
if(getSceneVersion(inData.scene.elements) !== this.previousSceneVersion) {
this.setDirty();
if(this.getSceneVersion(inData.scene.elements) !== this.previousSceneVersion) {
this.setDirty(3);
}
this.excalidrawAPI.updateScene({elements: sceneElements});
if(reloadFiles) this.loadSceneFiles();
@@ -1605,7 +1606,7 @@ export default class ExcalidrawView extends TextFileView {
justloaded,
);
if (
this.app.workspace.activeLeaf === this.leaf &&
this.app.workspace.getActiveViewOfType(ExcalidrawView) === this.leaf.view &&
this.excalidrawWrapperRef
) {
//.firstElmentChild solves this issue: https://github.com/zsviczian/obsidian-excalidraw-plugin/pull/346
@@ -1639,7 +1640,7 @@ export default class ExcalidrawView extends TextFileView {
this.plugin.settings.compress !== isCompressed &&
!this.isEditedAsMarkdownInOtherView()
) {
this.setDirty();
this.setDirty(4);
}
}
@@ -1652,7 +1653,8 @@ export default class ExcalidrawView extends TextFileView {
);
}
public setDirty() {
public setDirty(debug?:number) {
//console.log(debug);
this.semaphores.dirty = this.file?.path;
this.diskIcon.querySelector("svg").addClass("excalidraw-dirty");
}
@@ -1665,8 +1667,7 @@ export default class ExcalidrawView extends TextFileView {
this.semaphores.dirty = null;
const el = api.getSceneElements();
if (el) {
const getSceneVersion = this.ownerWindow.ExcalidrawLib.getSceneVersion;
this.previousSceneVersion = getSceneVersion(el);
this.previousSceneVersion = this.getSceneVersion(el);
}
this.diskIcon.querySelector("svg").removeClass("excalidraw-dirty");
}
@@ -1729,11 +1730,11 @@ export default class ExcalidrawView extends TextFileView {
await this.save();
this.plugin.openDrawing(
await this.plugin.convertSingleExcalidrawToMD(this.file),
false,
"active-pane",
);
}
onMoreOptionsMenu(menu: Menu) {
onPaneMenu(menu: Menu, source: string): void {
// Add a menu item to force the board to markdown view
if (!this.compatibilityMode) {
menu
@@ -1743,7 +1744,8 @@ export default class ExcalidrawView extends TextFileView {
.setIcon("document")
.onClick(() => {
this.openAsMarkdown();
});
})
.setSection("pane");
})
.addItem((item) => {
item
@@ -1751,13 +1753,15 @@ export default class ExcalidrawView extends TextFileView {
.setIcon(ICON_NAME)
.onClick(async () => {
this.exportExcalidraw();
});
})
.setSection("pane");
});
} else {
menu.addItem((item) => {
item
.setTitle(t("CONVERT_FILE"))
.onClick(() => this.convertExcalidrawToMD());
.onClick(() => this.convertExcalidrawToMD())
.setSection("pane");
});
}
menu
@@ -1765,6 +1769,7 @@ export default class ExcalidrawView extends TextFileView {
item
.setTitle(t("SAVE_AS_PNG"))
.setIcon(PNG_ICON_NAME)
.setSection("pane")
.onClick(async (ev) => {
if (!this.getScene || !this.file) {
return;
@@ -1784,12 +1789,14 @@ export default class ExcalidrawView extends TextFileView {
return;
}
this.savePNG();
});
})
.setSection("pane");
})
.addItem((item) => {
item
.setTitle(t("SAVE_AS_SVG"))
.setIcon(SVG_ICON_NAME)
.setSection("pane")
.onClick(async (ev) => {
if (!this.getScene || !this.file) {
return;
@@ -1811,7 +1818,7 @@ export default class ExcalidrawView extends TextFileView {
});
})
.addSeparator();
super.onMoreOptionsMenu(menu);
super.onPaneMenu(menu, source);
}
async getLibrary() {
@@ -1825,8 +1832,8 @@ export default class ExcalidrawView extends TextFileView {
while(!this.semaphores.scriptsReady) {
await sleep(50);
}
const React = this.ownerWindow.React;
const ReactDOM = this.ownerWindow.ReactDOM;
const React = this.plugin.getPackage(this.ownerWindow).react;
const ReactDOM = this.plugin.getPackage(this.ownerWindow).reactDOM;
//console.log("ExcalidrawView.instantiateExcalidraw()");
this.clearDirty();
const reactElement = React.createElement(() => {
@@ -1933,7 +1940,7 @@ export default class ExcalidrawView extends TextFileView {
}
};
this.ownerWindow.addEventListener("resize", onResize);
return () => this.ownerWindow.removeEventListener("resize", onResize);
return () => this.ownerWindow?.removeEventListener("resize", onResize);
}, [excalidrawWrapperRef]);
this.getSelectedTextElement = (): { id: string; text: string } => {
@@ -2209,7 +2216,7 @@ export default class ExcalidrawView extends TextFileView {
if (save) {
await this.save(false); //preventReload=false will ensure that markdown links are paresed and displayed correctly
} else {
this.setDirty();
this.setDirty(5);
}
return true;
};
@@ -2463,8 +2470,11 @@ export default class ExcalidrawView extends TextFileView {
}, 400);
}
};
const Excalidraw = this.ownerWindow.ExcalidrawLib.Excalidraw;
const getSceneVersion = this.ownerWindow.ExcalidrawLib.getSceneVersion;
const {
Excalidraw,
} = this.plugin.getPackage(this.ownerWindow).excalidrawLib;
const excalidrawDiv = React.createElement(
"div",
{
@@ -2586,7 +2596,7 @@ export default class ExcalidrawView extends TextFileView {
if (!this.semaphores.preventAutozoom) {
this.zoomToFit(false);
}
this.previousSceneVersion = getSceneVersion(et);
this.previousSceneVersion = this.getSceneVersion(et);
this.previousBackgroundColor = st.viewBackgroundColor;
return;
}
@@ -2602,15 +2612,16 @@ export default class ExcalidrawView extends TextFileView {
st.editingGroupId === null &&*/
st.editingLinearElement === null
) {
const sceneVersion = getSceneVersion(et);
const sceneVersion = this.getSceneVersion(et);
if (
(sceneVersion > 0 &&
((sceneVersion > 0 ||
(sceneVersion === 0 && et.length > 0)) && //Addressing the rare case when the last element is deleted from the scene
sceneVersion !== this.previousSceneVersion) ||
st.viewBackgroundColor !== this.previousBackgroundColor
) {
this.previousSceneVersion = sceneVersion;
this.previousBackgroundColor = st.viewBackgroundColor;
this.setDirty();
this.setDirty(6);
}
}
},
@@ -2858,7 +2869,7 @@ export default class ExcalidrawView extends TextFileView {
if (isDeleted) {
this.excalidrawData.deleteTextElement(textElement.id);
this.setDirty();
this.setDirty(7);
return [null, null, null];
}
@@ -2873,7 +2884,7 @@ export default class ExcalidrawView extends TextFileView {
) {
//the user made changes to the text or the text is missing from Excalidraw Data (recently copy/pasted)
//setTextElement will attempt a quick parse (without processing transclusions)
this.setDirty();
this.setDirty(8);
const [parseResultWrapped, parseResultOriginal, link] =
this.excalidrawData.setTextElement(
textElement.id,

View File

@@ -198,7 +198,7 @@ const createImageDiv = async (
if (src) {
plugin.openDrawing(
vault.getAbstractFileByPath(src) as TFile,
ev[CTRL_OR_CMD],
ev[CTRL_OR_CMD]?"new-pane":"active-pane",
);
} //.ctrlKey||ev.metaKey);
});
@@ -514,7 +514,7 @@ export const observer = new MutationObserver(async (m) => {
if (src) {
plugin.openDrawing(
vault.getAbstractFileByPath(src) as TFile,
ev[CTRL_OR_CMD],
ev[CTRL_OR_CMD]?"new-pane":"active-pane",
);
} //.ctrlKey||ev.metaKey);
});

View File

@@ -163,13 +163,10 @@ export class ScriptEngine {
name: `(Script) ${scriptName}`,
checkCallback: (checking: boolean) => {
if (checking) {
return (
this.plugin.app.workspace.activeLeaf.view.getViewType() ==
VIEW_TYPE_EXCALIDRAW
);
return Boolean(app.workspace.getActiveViewOfType(ExcalidrawView));
}
const view = this.plugin.app.workspace.activeLeaf.view;
if (view instanceof ExcalidrawView) {
const view = app.workspace.getActiveViewOfType(ExcalidrawView);
if (view) {
(async()=>{
const script = await this.plugin.app.vault.read(f);
if(script) {

View File

@@ -18,7 +18,7 @@ export const SCRIPT_INSTALL_FOLDER = "Downloaded";
export const fileid = customAlphabet("1234567890abcdef", 40);
export const REG_LINKINDEX_INVALIDCHARS = /[<>:"\\|?*#]/g;
export const REG_BLOCK_REF_CLEAN =
/\+|\/|~|=|%|\(|\)|{|}|,|\.|\$|!|\?|;|\[|]|\^|#|\*|<|>|&|@|\||\\|"|:/g;
/\+|\/|~|=|%|\(|\)|{|}|,|&|\.|\$|!|\?|;|\[|]|\^|#|\*|<|>|&|@|\||\\|"|:|\s/g;
export const IMAGE_TYPES = ["jpeg", "jpg", "png", "gif", "svg"];
export const MAX_IMAGE_SIZE = 500;
export const FRONTMATTER_KEY = "excalidraw-plugin";

View File

@@ -17,6 +17,40 @@ I develop this plugin as a hobby, spending most of my free time doing this. If y
<div class="ex-coffee-div"><a href="https://ko-fi.com/zsolt"><img src="https://cdn.ko-fi.com/cdn/kofi3.png?v=3" height=45></a></div>
`,
"1.7.5": `
# New
- Deployed sidebar for libraries panel from excalidraw.com ([#5274](https://github.com/excalidraw/excalidraw/pull/5274)). You can dock the library to the right side depending on the screen real estate available (i.e. does not work on mobiles).
# Fixed
- When copying 2 identical images from one drawing to another, the second image got corrupted in the process ([#672]https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/672)).
- When making a copy of an equation in a drawing and then without first closing/opening the file, immediately copying the new equation to another drawing, the equation did not get displayed until the file was closed and reopened.
- Copying a markdown embed from one drawing to another, in the destination the markdown embed appeared without the section/block reference and without the width & height (i.e. these settings had to be done again)
- Improved the parsing of section references in embeds. When you had ${String.fromCharCode(96)}&${String.fromCharCode(96)} in the section name in a markdown file, when embedding that markdown document into Excalidraw, the section reference did not work as expected ([#681 ](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/681)).
- Improved the logic for autosave to better detect changes to the document, and to reduce too frequent export of ${String.fromCharCode(96)}.png${String.fromCharCode(96)} and/or ${String.fromCharCode(96)}.svg${String.fromCharCode(96)} files, when auto export is enabled in plugin settings.
`,
"1.7.4": `
- Obsidian 0.15.3 support dragging and dropping work panes between Obsidian windows.
- Addressed Obsidian changes affecting the more-options menu.
- Addressed incompatibility with Obsidian Mobile 1.2.2.
`,
"1.7.3": `
Obsidian 0.15.3 support for dragging and dropping work panes between Obsidian windows.
`,
"1.7.2": `
Due to some of the changes to the code, I highly recommend restarting Obsidian after installing this update to Excalidraw.
# Fixed
- Stability improvements
- Opening links in new panes and creating new drawings from the file explorer works properly again
# New feature
- Two new command palette actions:
- Create a new drawing - IN A POPOUT WINDOW
- Create a new drawing - IN A POPOUT WINDOW - and embed into active document
![image|600](https://user-images.githubusercontent.com/14358394/175137800-88789f5d-f8e8-4371-a356-84f443aa6a50.png)
- Added setting to prefer opening the link in the popout window or in the main workspace.
![image|800](https://user-images.githubusercontent.com/14358394/175076326-1c8eee53-e512-4025-aedb-07881a732c69.png)
`,
"1.7.1": `
Support for Obsidian 0.15.0 popout windows. While there are no new features (apart from the popout window support) under the hood there were some major changes required to make this happen.
`,

View File

@@ -33,7 +33,7 @@ export class OpenFileDialog extends FuzzySuggestModal<TFile> {
if (this.containerEl.innerText.includes(EMPTY_MESSAGE)) {
this.plugin.createAndOpenDrawing(
`${this.plugin.settings.folder}/${this.inputEl.value}.excalidraw.md`,
this.onNewPane,
this.onNewPane?"new-pane":"active-pane",
);
this.close();
}
@@ -55,7 +55,7 @@ export class OpenFileDialog extends FuzzySuggestModal<TFile> {
onChooseItem(item: TFile): void {
switch (this.action) {
case openDialogAction.openFile:
this.plugin.openDrawing(item, this.onNewPane);
this.plugin.openDrawing(item, this.onNewPane?"new-pane":"active-pane");
break;
case openDialogAction.insertLinkToDrawing:
this.plugin.embedDrawing(item);

View File

@@ -219,7 +219,7 @@ export class GenericInputPrompt extends Modal {
}
private removeInputListener() {
this.inputComponent.inputEl.removeEventListener(
this.inputComponent?.inputEl?.removeEventListener(
"keydown",
this.submitEnterCallback,
);

View File

@@ -2,6 +2,8 @@ import { App, MarkdownRenderer, Modal } from "obsidian";
import ExcalidrawPlugin from "../main";
import { FIRST_RUN, RELEASE_NOTES } from "./Messages";
declare const PLUGIN_VERSION:string;
export class ReleaseNotes extends Modal {
private plugin: ExcalidrawPlugin;
private version: string;
@@ -23,9 +25,7 @@ export class ReleaseNotes extends Modal {
async onClose() {
this.contentEl.empty();
await this.plugin.loadSettings();
this.plugin.settings.previousRelease =
//@ts-ignore
this.app.plugins.manifests["obsidian-excalidraw-plugin"].version;
this.plugin.settings.previousRelease = PLUGIN_VERSION
await this.plugin.saveSettings();
}

View File

@@ -30,10 +30,12 @@ export default {
TRANSCLUDE_MOST_RECENT: "Transclude (embed) the most recently edited drawing",
NEW_IN_NEW_PANE: "Create a new drawing - IN A NEW PANE",
NEW_IN_ACTIVE_PANE: "Create a new drawing - IN THE CURRENT ACTIVE PANE",
NEW_IN_POPOUT_WINDOW: "Create a new drawing - IN A POPOUT WINDOW",
NEW_IN_NEW_PANE_EMBED:
"Create a new drawing - IN A NEW PANE - and embed into active document",
NEW_IN_ACTIVE_PANE_EMBED:
"Create a new drawing - IN THE CURRENT ACTIVE PANE - and embed into active document",
NEW_IN_POPOUT_WINDOW_EMBED: "Create a new drawing - IN A POPOUT WINDOW - and embedd into active document",
EXPORT_SVG: "Save as SVG next to the current file",
EXPORT_PNG: "Save as PNG next to the current file",
TOGGLE_LOCK: "Toggle Text Element edit RAW/PREVIEW",
@@ -189,10 +191,14 @@ export default {
"If you don't want text accidentally changing in your drawings use <code>[[links|with aliases]]</code>.",
ADJACENT_PANE_NAME: "Open in adjacent pane",
ADJACENT_PANE_DESC:
"When CTRL/CMD+SHIFT clicking a link in Excalidraw by default the plugin will open the link in a new pane. " +
"When CTRL/CMD+SHIFT clicking a link in Excalidraw, by default the plugin will open the link in a new pane. " +
"Turning this setting on, Excalidraw will first look for an existing adjacent pane, and try to open the link there. " +
"Excalidraw will first look too the right, then to the left, then down, then up. If no pane is found, Excalidraw will open " +
"a new pane.",
"Excalidraw will look for the adjacent pane based on your focus/navigation history, i.e. the workpane that was active before you " +
"activated Excalidraw.",
MAINWORKSPACE_PANE_NAME: "Open in main workspace",
MAINWORKSPACE_PANE_DESC:
"When CTRL/CMD+SHIFT clicking a link in Excalidraw, by default the plugin will open the link in a new pane in the current active window. " +
"Turning this setting on, Excalidraw will open the link in an existing or new pane in the main workspace. ",
LINK_BRACKETS_NAME: "Show <code>[[brackets]]</code> around links",
LINK_BRACKETS_DESC: `${
"In PREVIEW mode, when parsing Text Elements, place brackets around links. " +

View File

@@ -15,7 +15,7 @@ import {
loadMathJax,
request,
MetadataCache,
FrontMatterCache,
FrontMatterCache
} from "obsidian";
import {
BLANK_DRAWING,
@@ -82,6 +82,7 @@ import {
log,
setLeftHandedMode,
sleep,
debug,
} from "./utils/Utils";
import { getAttachmentsFolderAndFilePath, getNewOrAdjacentLeaf, getParentOfClass, isObsidianThemeDark } from "./utils/ObsidianUtils";
//import { OneOffs } from "./OneOffs";
@@ -95,6 +96,10 @@ import {
} from "./MarkdownPostProcessor";
import { FieldSuggester } from "./dialogs/FieldSuggester";
import { ReleaseNotes } from "./dialogs/ReleaseNotes";
import { decompressFromBase64 } from "lz-string";
import { Packages } from "./types";
import * as React from "react";
declare module "obsidian" {
interface App {
@@ -115,6 +120,12 @@ declare module "obsidian" {
}
}
declare const EXCALIDRAW_PACKAGES:string;
declare const react:any;
declare const reactDOM:any;
declare const excalidrawLib: any;
declare const PLUGIN_VERSION:string;
export default class ExcalidrawPlugin extends Plugin {
private excalidrawFiles: Set<TFile> = new Set<TFile>();
public excalidrawFileModes: { [file: string]: string } = {};
@@ -139,7 +150,7 @@ export default class ExcalidrawPlugin extends Plugin {
public opencount: number = 0;
public ea: ExcalidrawAutomate;
//A master list of fileIds to facilitate copy / paste
public filesMaster: Map<FileId, { path: string; hasSVGwithBitmap: boolean }> =
public filesMaster: Map<FileId, { path: string; hasSVGwithBitmap: boolean; blockrefData: string }> =
null; //fileId, path
public equationsMaster: Map<FileId, string> = null; //fileId, formula
public mathjax: any = null;
@@ -147,15 +158,37 @@ export default class ExcalidrawPlugin extends Plugin {
public mathjaxLoaderFinished: boolean = false;
public scriptEngine: ScriptEngine;
public fourthFontDef: string = VIRGIL_FONT;
private packageMap: WeakMap<Window,Packages> = new WeakMap<Window,Packages>();
constructor(app: App, manifest: PluginManifest) {
super(app, manifest);
this.filesMaster = new Map<
FileId,
{ path: string; hasSVGwithBitmap: boolean }
{ path: string; hasSVGwithBitmap: boolean; blockrefData: string }
>();
this.equationsMaster = new Map<FileId, string>();
}
public getPackage(win:Window):Packages {
if(win===window) {
return {react, reactDOM, excalidrawLib};
}
if(this.packageMap.has(win)) {
return this.packageMap.get(win);
}
//@ts-ignore
const {react:r, reactDOM:rd, excalidrawLib:e} = win.eval.call(win,
`(function() {
${decompressFromBase64(EXCALIDRAW_PACKAGES)};
return {react:React,reactDOM:ReactDOM,excalidrawLib:ExcalidrawLib};
})()`);
this.packageMap.set(win,{react:r, reactDOM:rd, excalidrawLib:e});
return {react:r, reactDOM:rd, excalidrawLib:e};
}
async onload() {
addIcon(ICON_NAME, EXCALIDRAW_ICON);
addIcon(SCRIPTENGINE_ICON_NAME, SCRIPTENGINE_ICON);
@@ -188,29 +221,16 @@ export default class ExcalidrawPlugin extends Plugin {
//https://github.com/mgmeyers/obsidian-kanban/blob/44118e25661bff9ebfe54f71ae33805dc88ffa53/src/main.ts#L267
this.registerMonkeyPatches();
if (!this.app.isMobile) {
const electron: string = process?.versions?.electron;
if (electron && electron?.startsWith("8.")) {
new Notice(
`You are running an older version of the electron Browser (${electron}). If Excalidraw does not start up, please reinstall Obsidian with the latest installer and try again.`,
10000,
);
}
}
// 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.imageElementNotice;
const version: string =
//@ts-ignore
this.app.plugins.manifests["obsidian-excalidraw-plugin"].version;
if (version > this.settings.previousRelease) {
if (PLUGIN_VERSION > this.settings.previousRelease) {
new ReleaseNotes(
this.app,
this,
obsidianJustInstalled ? null : version,
obsidianJustInstalled ? null : PLUGIN_VERSION,
).open();
}
}
@@ -645,7 +665,7 @@ export default class ExcalidrawPlugin extends Plugin {
this.addRibbonIcon(ICON_NAME, t("CREATE_NEW"), async (e) => {
this.createAndOpenDrawing(
getDrawingFilename(this.settings),
e[CTRL_OR_CMD],
e[CTRL_OR_CMD]?"new-pane":"active-pane",
); //.ctrlKey||e.metaKey);
});
@@ -663,7 +683,7 @@ export default class ExcalidrawPlugin extends Plugin {
}
this.createAndOpenDrawing(
getDrawingFilename(this.settings),
false,
"active-pane",
folderpath,
);
});
@@ -735,7 +755,7 @@ export default class ExcalidrawPlugin extends Plugin {
name: t("TRANSCLUDE"),
checkCallback: (checking: boolean) => {
if (checking) {
return this.app.workspace.activeLeaf.view.getViewType() == "markdown";
return Boolean(this.app.workspace.getActiveViewOfType(MarkdownView))
}
this.openDialog.start(openDialogAction.insertLinkToDrawing, false);
return true;
@@ -748,7 +768,7 @@ export default class ExcalidrawPlugin extends Plugin {
checkCallback: (checking: boolean) => {
if (checking) {
return (
this.app.workspace.activeLeaf.view.getViewType() == "markdown" &&
Boolean(this.app.workspace.getActiveViewOfType(MarkdownView)) &&
this.lastActiveExcalidrawFilePath != null
);
}
@@ -767,7 +787,7 @@ export default class ExcalidrawPlugin extends Plugin {
id: "excalidraw-autocreate",
name: t("NEW_IN_NEW_PANE"),
callback: () => {
this.createAndOpenDrawing(getDrawingFilename(this.settings), true);
this.createAndOpenDrawing(getDrawingFilename(this.settings), "new-pane");
},
});
@@ -775,11 +795,21 @@ export default class ExcalidrawPlugin extends Plugin {
id: "excalidraw-autocreate-on-current",
name: t("NEW_IN_ACTIVE_PANE"),
callback: () => {
this.createAndOpenDrawing(getDrawingFilename(this.settings), false);
this.createAndOpenDrawing(getDrawingFilename(this.settings), "active-pane");
},
});
const insertDrawingToDoc = async (inNewPane: boolean) => {
this.addCommand({
id: "excalidraw-autocreate-popout",
name: t("NEW_IN_POPOUT_WINDOW"),
callback: () => {
this.createAndOpenDrawing(getDrawingFilename(this.settings), "popout-window");
},
});
const insertDrawingToDoc = async (
location: "active-pane"|"new-pane"|"popout-window"
) => {
const activeView = this.app.workspace.getActiveViewOfType(MarkdownView);
if (!activeView) {
return;
@@ -799,7 +829,7 @@ export default class ExcalidrawPlugin extends Plugin {
).folder;
const file = await this.createDrawing(filename, folder);
await this.embedDrawing(file);
this.openDrawing(file, inNewPane);
this.openDrawing(file, location);
};
this.addCommand({
@@ -807,9 +837,9 @@ export default class ExcalidrawPlugin extends Plugin {
name: t("NEW_IN_NEW_PANE_EMBED"),
checkCallback: (checking: boolean) => {
if (checking) {
return this.app.workspace.activeLeaf.view.getViewType() == "markdown";
return Boolean(this.app.workspace.getActiveViewOfType(MarkdownView));
}
insertDrawingToDoc(true);
insertDrawingToDoc("new-pane");
return true;
},
});
@@ -819,25 +849,36 @@ export default class ExcalidrawPlugin extends Plugin {
name: t("NEW_IN_ACTIVE_PANE_EMBED"),
checkCallback: (checking: boolean) => {
if (checking) {
return this.app.workspace.activeLeaf.view.getViewType() == "markdown";
return Boolean(this.app.workspace.getActiveViewOfType(MarkdownView));
}
insertDrawingToDoc(false);
insertDrawingToDoc("active-pane");
return true;
},
});
this.addCommand({
id: "excalidraw-autocreate-and-embed-popout",
name: t("NEW_IN_POPOUT_WINDOW_EMBED"),
checkCallback: (checking: boolean) => {
if (checking) {
return Boolean(this.app.workspace.getActiveViewOfType(MarkdownView));
}
insertDrawingToDoc("popout-window");
return true;
},
});
this.addCommand({
id: "export-svg",
name: t("EXPORT_SVG"),
checkCallback: (checking: boolean) => {
if (checking) {
return (
this.app.workspace.activeLeaf.view.getViewType() ==
VIEW_TYPE_EXCALIDRAW
Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
);
}
const view = this.app.workspace.activeLeaf.view;
if (view instanceof ExcalidrawView) {
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
if (view) {
view.saveSVG();
return true;
}
@@ -851,12 +892,11 @@ export default class ExcalidrawPlugin extends Plugin {
checkCallback: (checking: boolean) => {
if (checking) {
return (
this.app.workspace.activeLeaf.view.getViewType() ===
VIEW_TYPE_EXCALIDRAW
Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
);
}
const view = this.app.workspace.activeLeaf.view;
if (view instanceof ExcalidrawView) {
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
if (view) {
search(view);
return true;
}
@@ -870,12 +910,11 @@ export default class ExcalidrawPlugin extends Plugin {
checkCallback: (checking: boolean) => {
if (checking) {
return (
this.app.workspace.activeLeaf.view.getViewType() ===
VIEW_TYPE_EXCALIDRAW
Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
);
}
const view = this.app.workspace.activeLeaf.view;
if (view instanceof ExcalidrawView) {
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
if (view) {
if (view.isFullscreen()) {
view.exitFullscreen();
} else {
@@ -887,67 +926,17 @@ export default class ExcalidrawPlugin extends Plugin {
},
});
/* this.addCommand({
id: "ocr",
name: "Test OCR",//t("EXPORT_PNG"),
checkCallback: (checking: boolean) => {
if (checking) {
return (
this.app.workspace.activeLeaf.view.getViewType() ===
//@ts-ignore
VIEW_TYPE_EXCALIDRAW && typeof Tesseract !== "undefined"
);
}
const view = this.app.workspace.activeLeaf.view;
if (view instanceof ExcalidrawView) {
//@ts-ignore
const worker = Tesseract.createWorker({logger: m => console.log(m)});
//@ts-ignore
Tesseract.setLogging(true);
const exportSettings: ExportSettings = {
withBackground: true,
withTheme: false,
};
const blobToBase64 = async (blob:any) => {
return new Promise((resolve, _) => {
const reader = new FileReader();
reader.onloadend = () => resolve(reader.result);
reader.readAsDataURL(blob);
});
}
(async () => {
const png = await getPNG(
view.getScene(),
exportSettings,
3,
);
await worker.load();
await worker.loadLanguage('https://https://raw.githubusercontent.com/thecodingone/trained-tesseract-handwriting-fonts/blob/master/eng.traineddata');
await worker.initialize('https://raw.githubusercontent.com/thecodingone/trained-tesseract-handwriting-fonts/blob/master/eng.traineddata');
const { data: { text } } = await worker.recognize(await blobToBase64(png));
console.log(text);
await worker.terminate();
})();
return true;
}
return false;
},
});*/
this.addCommand({
id: "export-png",
name: t("EXPORT_PNG"),
checkCallback: (checking: boolean) => {
if (checking) {
return (
this.app.workspace.activeLeaf.view.getViewType() ==
VIEW_TYPE_EXCALIDRAW
Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
);
}
const view = this.app.workspace.activeLeaf.view;
if (view instanceof ExcalidrawView) {
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
if (view) {
view.savePNG();
return true;
}
@@ -962,16 +951,15 @@ export default class ExcalidrawPlugin extends Plugin {
checkCallback: (checking: boolean) => {
if (checking) {
if (
this.app.workspace.activeLeaf.view.getViewType() ===
VIEW_TYPE_EXCALIDRAW
Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
) {
return !(this.app.workspace.activeLeaf.view as ExcalidrawView)
return !(this.app.workspace.getActiveViewOfType(ExcalidrawView))
.compatibilityMode;
}
return false;
}
const view = this.app.workspace.activeLeaf.view;
if (view instanceof ExcalidrawView) {
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
if (view) {
view.changeTextMode(
view.textMode === TextMode.parsed ? TextMode.raw : TextMode.parsed,
);
@@ -986,11 +974,10 @@ export default class ExcalidrawPlugin extends Plugin {
name: t("DELETE_FILE"),
checkCallback: (checking: boolean) => {
if (checking) {
const view = this.app.workspace.activeLeaf.view;
return view instanceof ExcalidrawView;
return Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
}
const view = this.app.workspace.activeLeaf.view;
if (view instanceof ExcalidrawView) {
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
if (view) {
this.ea.reset();
this.ea.setView(view);
const el = this.ea.getViewSelectedElement();
@@ -1023,11 +1010,10 @@ export default class ExcalidrawPlugin extends Plugin {
name: t("INSERT_LINK"),
checkCallback: (checking: boolean) => {
if (checking) {
const view = this.app.workspace.activeLeaf.view;
return view instanceof ExcalidrawView;
return Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
}
const view = this.app.workspace.activeLeaf.view;
if (view instanceof ExcalidrawView) {
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
if (view) {
this.insertLinkDialog.start(view.file.path, view.addText);
return true;
}
@@ -1041,11 +1027,10 @@ export default class ExcalidrawPlugin extends Plugin {
name: t("INSERT_LINK_TO_ELEMENT"),
checkCallback: (checking: boolean) => {
if (checking) {
const view = this.app.workspace.activeLeaf.view;
return view instanceof ExcalidrawView;
return Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
}
const view = this.app.workspace.activeLeaf.view;
if (view instanceof ExcalidrawView) {
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
if (view) {
view.copyLinkToSelectedElementToClipboard();
return true;
}
@@ -1058,11 +1043,10 @@ export default class ExcalidrawPlugin extends Plugin {
name: t("INSERT_IMAGE"),
checkCallback: (checking: boolean) => {
if (checking) {
const view = this.app.workspace.activeLeaf.view;
return view instanceof ExcalidrawView;
return Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
}
const view = this.app.workspace.activeLeaf.view;
if (view instanceof ExcalidrawView) {
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
if (view) {
this.insertImageDialog.start(view);
return true;
}
@@ -1075,13 +1059,9 @@ export default class ExcalidrawPlugin extends Plugin {
name: t("READ_RELEASE_NOTES"),
checkCallback: (checking: boolean) => {
if (checking) {
const view = this.app.workspace.activeLeaf.view;
return view instanceof ExcalidrawView;
return Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
}
const version: string =
//@ts-ignore
this.app.plugins.manifests["obsidian-excalidraw-plugin"].version;
new ReleaseNotes(this.app, this, version).open();
new ReleaseNotes(this.app, this, PLUGIN_VERSION).open();
return true;
},
});
@@ -1091,8 +1071,8 @@ export default class ExcalidrawPlugin extends Plugin {
name: t("TRAY_MODE"),
checkCallback: (checking: boolean) => {
if (checking) {
const view = this.app.workspace.activeLeaf.view;
if (!(view instanceof ExcalidrawView) || !view.excalidrawRef) {
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
if (!view || !view.excalidrawRef) {
return false;
}
const st = view.excalidrawAPI.getAppState();
@@ -1101,8 +1081,8 @@ export default class ExcalidrawPlugin extends Plugin {
}
return true;
}
const view = this.app.workspace.activeLeaf.view;
if (view instanceof ExcalidrawView && view.excalidrawAPI) {
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
if (view && view.excalidrawAPI) {
view.toggleTrayMode();
return true;
}
@@ -1115,11 +1095,10 @@ export default class ExcalidrawPlugin extends Plugin {
name: t("INSERT_MD"),
checkCallback: (checking: boolean) => {
if (checking) {
const view = this.app.workspace.activeLeaf.view;
return view instanceof ExcalidrawView;
return Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
}
const view = this.app.workspace.activeLeaf.view;
if (view instanceof ExcalidrawView) {
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
if (view) {
this.insertMDDialog.start(view);
return true;
}
@@ -1132,13 +1111,10 @@ export default class ExcalidrawPlugin extends Plugin {
name: t("INSERT_LATEX"),
checkCallback: (checking: boolean) => {
if (checking) {
return (
this.app.workspace.activeLeaf.view.getViewType() ==
VIEW_TYPE_EXCALIDRAW
);
return Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView));
}
const view = this.app.workspace.activeLeaf.view;
if (view instanceof ExcalidrawView) {
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
if (view) {
insertLaTeXToView(view);
return true;
}
@@ -1158,25 +1134,30 @@ export default class ExcalidrawPlugin extends Plugin {
if (checking) {
if (
this.app.workspace.activeLeaf.view.getViewType() ==
VIEW_TYPE_EXCALIDRAW
Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView))
) {
return !(this.app.workspace.activeLeaf.view as ExcalidrawView)
return !(this.app.workspace.getActiveViewOfType(ExcalidrawView))
.compatibilityMode;
}
return fileIsExcalidraw;
}
const activeLeaf = this.app.workspace.activeLeaf;
if (activeLeaf?.view && activeLeaf.view instanceof ExcalidrawView) {
const excalidrawView = this.app.workspace.getActiveViewOfType(ExcalidrawView)
if (excalidrawView) {
const activeLeaf = excalidrawView.leaf;
this.excalidrawFileModes[(activeLeaf as any).id || activeFile.path] =
"markdown";
this.setMarkdownView(activeLeaf);
} else if (fileIsExcalidraw) {
return;
}
const markdownView = this.app.workspace.getActiveViewOfType(MarkdownView)
if (markdownView && fileIsExcalidraw) {
const activeLeaf = markdownView.leaf;
this.excalidrawFileModes[(activeLeaf as any).id || activeFile.path] =
VIEW_TYPE_EXCALIDRAW;
this.setExcalidrawView(activeLeaf);
return;
}
},
});
@@ -1186,9 +1167,9 @@ export default class ExcalidrawPlugin extends Plugin {
name: t("CONVERT_NOTE_TO_EXCALIDRAW"),
checkCallback: (checking) => {
const activeFile = this.app.workspace.getActiveFile();
const activeLeaf = this.app.workspace.activeLeaf;
const activeView = this.app.workspace.getActiveViewOfType(MarkdownView);
if (!activeFile || !activeLeaf) {
if (!activeFile || !activeView) {
return false;
}
@@ -1197,13 +1178,14 @@ export default class ExcalidrawPlugin extends Plugin {
if (checking) {
return isFileEmpty;
}
if (isFileEmpty) {
(async () => {
await this.app.vault.modify(
activeFile,
await this.getBlankDrawing(),
);
this.setExcalidrawView(activeLeaf);
this.setExcalidrawView(activeView.leaf);
})();
}
},
@@ -1337,7 +1319,7 @@ export default class ExcalidrawPlugin extends Plugin {
// Add a menu item to go back to Excalidraw view
this.register(
around(MarkdownView.prototype, {
onMoreOptionsMenu(next) {
onPaneMenu(next) {
return function (menu: Menu) {
const file = this.file;
const cache = file
@@ -1357,6 +1339,7 @@ export default class ExcalidrawPlugin extends Plugin {
item
.setTitle(t("OPEN_AS_EXCALIDRAW"))
.setIcon(ICON_NAME)
.setSection("pane")
.onClick(() => {
self.excalidrawFileModes[this.leaf.id || file.path] =
VIEW_TYPE_EXCALIDRAW;
@@ -1364,7 +1347,6 @@ export default class ExcalidrawPlugin extends Plugin {
});
})
.addSeparator();
next.call(this, menu);
};
},
@@ -1505,7 +1487,9 @@ export default class ExcalidrawPlugin extends Plugin {
if (previouslyActiveEV.leaf != leaf) {
//if loading new view to same leaf then don't save. Excalidarw view will take care of saving anyway.
//avoid double saving
await previouslyActiveEV.save(true); //this will update transclusions in the drawing
if(previouslyActiveEV.semaphores.dirty) {
await previouslyActiveEV.save(true); //this will update transclusions in the drawing
}
}
if (previouslyActiveEV.file) {
self.triggerEmbedUpdates(previouslyActiveEV.file.path);
@@ -1712,21 +1696,10 @@ export default class ExcalidrawPlugin extends Plugin {
document.body.removeChild(this.mathjaxDiv);
}
const visitedDocs = new Set<Document>();
app.workspace.iterateAllLeaves((leaf)=>{
const ownerDocument = app.isMobile?document:leaf.view.containerEl.ownerDocument;
if(!ownerDocument) return;
if(visitedDocs.has(ownerDocument)) return;
visitedDocs.add(ownerDocument);
const el = ownerDocument.getElementById("excalidraw-script");
if(el) {
ownerDocument.body.removeChild(el);
const win = ownerDocument.defaultView;
delete win.React;
delete win.ReactDOM;
delete win.ExcalidrawLib;
}
Object.values(this.packageMap).forEach((p:Packages)=>{
delete p.excalidrawLib;
delete p.reactDOM;
delete p.react;
})
}
@@ -1819,12 +1792,20 @@ export default class ExcalidrawPlugin extends Plugin {
})
}
public openDrawing(drawingFile: TFile, onNewPane: boolean) {
let leaf = this.app.workspace.activeLeaf;
if (!leaf || onNewPane) {
leaf = getNewOrAdjacentLeaf(this, app.workspace.activeLeaf);
public openDrawing(
drawingFile: TFile,
location: "active-pane"|"new-pane"|"popout-window"
) {
let leaf: WorkspaceLeaf;
if(location === "popout-window") {
//@ts-ignore
leaf = app.workspace.openPopoutLeaf();
}
else {
leaf = this.app.workspace.getLeaf(false);
if ((leaf.view.getViewType() !== 'empty') && (location === "new-pane")) {
leaf = getNewOrAdjacentLeaf(this, leaf)
}
}
leaf.setViewState({
@@ -1911,20 +1892,32 @@ export default class ExcalidrawPlugin extends Plugin {
);
await checkAndCreateFolder(this.app.vault, folderpath); //create folder if it does not exist
const fname = getNewUniqueFilepath(this.app.vault, filename, folderpath);
return await this.app.vault.create(
const file = await this.app.vault.create(
fname,
initData ?? (await this.getBlankDrawing()),
);
//wait for metadata cache
let counter = 0;
while(file instanceof TFile && !this.isExcalidrawFile(file) && counter++<10) {
await sleep(50);
}
if(counter > 10) {
errorlog({file, error: "new drawing not recognized as an excalidraw file", fn: this.createDrawing});
}
return file;
}
public async createAndOpenDrawing(
filename: string,
onNewPane: boolean,
location: "active-pane"|"new-pane"|"popout-window",
foldername?: string,
initData?: string,
): Promise<string> {
const file = await this.createDrawing(filename, foldername, initData);
this.openDrawing(file, onNewPane);
this.openDrawing(file, location);
return file.path;
}

View File

@@ -11,6 +11,7 @@ import { ReleaseNotes } from "../dialogs/ReleaseNotes";
import { ScriptIconMap } from "../Scripts";
import { getIMGFilename } from "../utils/FileUtils";
declare const PLUGIN_VERSION:string;
const dark = '<svg style="stroke:#ced4da;#212529;color:#ced4da;fill:#ced4da" ';
const light = '<svg style="stroke:#212529;color:#212529;fill:#212529" ';
@@ -49,7 +50,7 @@ export class ToolsPanel extends React.Component<PanelProps, PanelState> {
constructor(props: PanelProps) {
super(props);
const react = props.view.ownerWindow.React;
const react = props.view.plugin.getPackage(props.view.ownerWindow).react;
this.containerRef = react.createRef();
this.state = {
visible: props.visible,
@@ -193,7 +194,7 @@ export class ToolsPanel extends React.Component<PanelProps, PanelState> {
: "none",
height: "fit-content",
maxHeight: "400px",
zIndex: 3,
zIndex: 5,
}}
>
<div
@@ -227,8 +228,8 @@ export class ToolsPanel extends React.Component<PanelProps, PanelState> {
};
const onPointerUp = () => {
this.props.view.ownerDocument.removeEventListener("pointerup", onPointerUp);
this.props.view.ownerDocument.removeEventListener("pointermove", onDrag);
this.props.view.ownerDocument?.removeEventListener("pointerup", onPointerUp);
this.props.view.ownerDocument?.removeEventListener("pointermove", onDrag);
};
event.preventDefault();
@@ -278,15 +279,10 @@ export class ToolsPanel extends React.Component<PanelProps, PanelState> {
key={"release-notes"}
title={t("READ_RELEASE_NOTES")}
action={() => {
const version: string =
//@ts-ignore
this.props.view.app.plugins.manifests[
"obsidian-excalidraw-plugin"
].version;
new ReleaseNotes(
this.props.view.app,
this.props.view.plugin,
version,
PLUGIN_VERSION,
).open();
}}
icon={ICONS.releaseNotes}

View File

@@ -44,6 +44,7 @@ export interface ExcalidrawSettings {
zoomToFitOnResize: boolean;
zoomToFitMaxLevel: number;
openInAdjacentPane: boolean;
openInMainWorkspace: boolean;
showLinkBrackets: boolean;
linkPrefix: string;
urlPrefix: string;
@@ -133,6 +134,7 @@ export const DEFAULT_SETTINGS: ExcalidrawSettings = {
hoverPreviewWithoutCTRL: false,
linkOpacity: 1,
openInAdjacentPane: false,
openInMainWorkspace: true,
showLinkBrackets: true,
allowCtrlClick: true,
forceWrap: false,
@@ -565,6 +567,19 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
}),
);
new Setting(containerEl)
.setName(t("MAINWORKSPACE_PANE_NAME"))
.setDesc(fragWithHTML(t("MAINWORKSPACE_PANE_DESC")))
.addToggle((toggle) =>
toggle
.setValue(this.plugin.settings.openInMainWorkspace)
.onChange(async (value) => {
this.plugin.settings.openInMainWorkspace = value;
this.applySettingsUpdate(true);
}),
);
new Setting(containerEl)
.setName(t("LINK_BRACKETS_NAME"))
.setDesc(fragWithHTML(t("LINK_BRACKETS_DESC")))

7
src/types.d.ts vendored
View File

@@ -6,8 +6,15 @@ import { ExcalidrawAutomate } from "./ExcalidrawAutomate";
import ExcalidrawView, { ExportSettings } from "./ExcalidrawView";
import ExcalidrawPlugin from "./main";
export type ConnectionPoint = "top" | "bottom" | "left" | "right" | null;
export type Packages = {
react: any,
reactDOM: any,
excalidrawLib: any,
}
export interface ExcalidrawAutomateInterface {
plugin: ExcalidrawPlugin;
elementsDict: {[key:string]:any}; //contains the ExcalidrawElements currently edited in Automate indexed by el.id

View File

@@ -21,45 +21,38 @@ export const getNewOrAdjacentLeaf = (
plugin: ExcalidrawPlugin,
leaf: WorkspaceLeaf
): WorkspaceLeaf => {
const inHoverEditorLeaf = leaf.view?.containerEl
? getParentOfClass(leaf.view.containerEl, "popover") !== null
: false;
if (inHoverEditorLeaf) {
const mainLeaves = app.workspace.getLayout().main.children.filter((c:any) => c.type === "leaf");
if(mainLeaves.length === 0) {
//@ts-ignore
return app.workspace.createLeafInParent(app.workspace.rootSplit);
if(plugin.settings.openInMainWorkspace) {
leaf.view.navigation = false;
const mainLeaf = app.workspace.getLeaf(false)
leaf.view.navigation = true;
if(plugin.settings.openInAdjacentPane || mainLeaf.view.getViewType() === 'empty') {
return mainLeaf;
}
const targetLeaf = app.workspace.getLeafById(mainLeaves[0].id);
if (plugin.settings.openInAdjacentPane) {
return targetLeaf;
}
return plugin.app.workspace.createLeafBySplit(targetLeaf);
return app.workspace.createLeafBySplit(mainLeaf);
}
if (plugin.settings.openInAdjacentPane) {
let leafToUse = plugin.app.workspace.getAdjacentLeafInDirection(
leaf,
"right"
);
if (!leafToUse) {
leafToUse = plugin.app.workspace.getAdjacentLeafInDirection(leaf, "left");
//if in popout window
if(leaf.view.containerEl.ownerDocument !== document) {
const popoutLeaves = new Set<WorkspaceLeaf>();
app.workspace.iterateAllLeaves(l=>{
if(l !== leaf && l.view.navigation && l.view.containerEl.ownerDocument === leaf.view.containerEl.ownerDocument) {
popoutLeaves.add(l);
}
});
if(popoutLeaves.size === 0) {
return app.workspace.getLeaf(true);
}
return Array.from(popoutLeaves)[0];
}
if (!leafToUse) {
leafToUse = plugin.app.workspace.getAdjacentLeafInDirection(
leaf,
"bottom"
);
}
if (!leafToUse) {
leafToUse = plugin.app.workspace.getAdjacentLeafInDirection(leaf, "top");
}
if (!leafToUse) {
leafToUse = plugin.app.workspace.createLeafBySplit(leaf);
}
return leafToUse;
leaf.view.navigation = false;
const leafToUse = app.workspace.getLeaf(false)
leaf.view.navigation = true;
return leafToUse
}
return plugin.app.workspace.createLeafBySplit(leaf);
};

View File

@@ -23,15 +23,13 @@ import { ExportSettings } from "../ExcalidrawView";
import { compressToBase64, decompressFromBase64 } from "lz-string";
import { getIMGFilename } from "./FileUtils";
declare global {
interface Window {
ExcalidrawLib: any;
}
}
declare const PLUGIN_VERSION:string;
const {
exportToSvg,
exportToBlob,
} = window.ExcalidrawLib;
//@ts-ignore
} = excalidrawLib;
declare module "obsidian" {
interface Workspace {
@@ -51,8 +49,6 @@ export const checkExcalidrawVersion = async (app: App) => {
return;
}
versionUpdateChecked = true;
//@ts-ignore
const manifest = app.plugins.manifests[PLUGIN_ID];
try {
const gitAPIrequest = async () => {
@@ -73,9 +69,9 @@ export const checkExcalidrawVersion = async (app: App) => {
.filter((el: any) => el.version.match(/^\d+\.\d+\.\d+$/))
.sort((el1: any, el2: any) => el2.published - el1.published)[0].version;
if (latestVersion > manifest.version) {
if (latestVersion > PLUGIN_VERSION) {
new Notice(
`A newer version of Excalidraw is available in Community Plugins.\n\nYou are using ${manifest.version}.\nThe latest is ${latestVersion}`,
`A newer version of Excalidraw is available in Community Plugins.\n\nYou are using ${PLUGIN_VERSION}.\nThe latest is ${latestVersion}`,
);
}
} catch (e) {

3
testloader.js Normal file

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,6 @@
{
"1.7.1": "0.15.2",
"1.7.5": "0.15.3",
"1.7.2": "0.15.2",
"1.6.34": "0.12.16",
"1.4.2": "0.11.13"
}

1164
yarn.lock

File diff suppressed because it is too large Load Diff