Compare commits

..

9 Commits

Author SHA1 Message Date
zsviczian
99a7e74825 Updated rollup to work with React 19
Resolved mobile tabs not visible (hack) due to Obsidain 18.x changes
2025-03-09 11:29:19 +01:00
zsviczian
304cef4d7d Merge pull request #2223 from dmscode/master
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Update zh-cn.ts to 1215266
2025-03-08 09:28:03 +01:00
稻米鼠
7dba9b88dc Merge branch 'zsviczian:master' into master 2025-02-05 07:46:30 +08:00
zsviczian
bfb5de1525 2.8.3
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-02-04 21:25:13 +01:00
zsviczian
8071a2888b 2.8.2
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-02-02 22:43:35 +01:00
zsviczian
8b9abb13d0 2.8.2-beta-1
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
2025-02-02 07:14:56 +01:00
dmscode
e6fca1a2d0 Update zh-cn.ts to a9cad8c 2025-01-25 08:09:25 +08:00
稻米鼠
a9cad8c9f1 Merge branch 'zsviczian:master' into master 2025-01-25 07:56:55 +08:00
dmscode
01a88a25a2 Update zh-cn.ts to 1215266 2025-01-23 08:33:03 +08:00
26 changed files with 1557 additions and 1488 deletions

View File

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

2680
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -16,21 +16,20 @@
"build:mathjax": "cd MathjaxToSVG && npm run build",
"build:all": "npm run build:mathjax && npm run build",
"dev:mathjax": "cd MathjaxToSVG && npm run dev",
"dev:all": "npm run dev:mathjax && npm run dev",
"build:lang": "node ./scripts/compressLanguages.js"
"dev:all": "npm run dev:mathjax && npm run dev"
},
"keywords": [],
"author": "",
"license": "MIT",
"dependencies": {
"dependencies": {
"@popperjs/core": "^2.11.8",
"@zsviczian/excalidraw": "0.17.6-29",
"@zsviczian/excalidraw": "0.18.0-0",
"chroma-js": "^2.4.2",
"clsx": "^2.0.0",
"@zsviczian/colormaster": "^1.2.2",
"gl-matrix": "^3.4.3",
"js-yaml": "^4.1.0",
"lucide-react": "^0.263.1",
"lucide-react": "^0.479.0",
"mathjax-full": "^3.2.2",
"monkey-around": "^2.3.0",
"nanoid": "^4.0.2",

View File

@@ -24,6 +24,29 @@ const isProd = (process.env.NODE_ENV === "production");
const isLib = (process.env.NODE_ENV === "lib");
console.log(`Running: ${process.env.NODE_ENV}; isProd: ${isProd}; isLib: ${isLib}`);
// Excalidraw React 19 compatiblity shim
// Create JSX runtime compatibility layer
const jsxRuntimeShim = `
const jsx = (type, props, key) => {
return React.createElement(type, props);
};
const jsxs = (type, props, key) => {
return React.createElement(type, props);
};
const Fragment = React.Fragment;
React.jsx = jsx;
React.jsxs = jsxs;
React.Fragment = Fragment;
React.jsxRuntime = { jsx, jsxs, Fragment };
window.__WEBPACK_EXTERNAL_MODULE_react_jsx_runtime__ = { jsx, jsxs, Fragment };
window.__WEBPACK_EXTERNAL_MODULE_react_jsx_dev_runtime__ = { jsx, jsxs, Fragment, jsxDEV: jsx };
window['react/jsx-runtime'] = { jsx, jsxs, Fragment };
window['react/jsx-dev-runtime'] = { jsx, jsxs, Fragment, jsxDEV: jsx };
`;
const mathjaxtosvg_pkg = isLib ? "" : fs.readFileSync("./MathjaxToSVG/dist/index.js", "utf8");
const LANGUAGES = ['ru', 'zh-cn']; //english is not compressed as it is always loaded by default
@@ -99,7 +122,7 @@ const packageString = isLib
? ""
: ';const INITIAL_TIMESTAMP=Date.now();' + lzstring_pkg +
'\nlet REACT_PACKAGES = `' +
jsesc(react_pkg + reactdom_pkg, { quotes: 'backtick' }) +
jsesc(react_pkg + reactdom_pkg + jsxRuntimeShim, { quotes: 'backtick' }) +
'`;\n' +
'const unpackExcalidraw = () => LZString.decompressFromBase64("' + LZString.compressToBase64(excalidraw_pkg) + '");\n' +
'let {react, reactDOM } = new Function(`${REACT_PACKAGES}; return {react: React, reactDOM: ReactDOM};`)();\n' +

View File

@@ -232,6 +232,39 @@ export const FRONTMATTER_KEYS:{[key:string]: {name: string, type: string, depric
"open-as-markdown": {name: "excalidraw-open-md", type: "checkbox"},
};
export const CaptureUpdateAction = {
/**
* Immediately undoable.
*
* Use for updates which should be captured.
* Should be used for most of the local updates.
*
* These updates will _immediately_ make it to the local undo / redo stacks.
*/
IMMEDIATELY: "IMMEDIATELY",
/**
* Never undoable.
*
* Use for updates which should never be recorded, such as remote updates
* or scene initialization.
*
* These updates will _never_ make it to the local undo / redo stacks.
*/
NEVER: "NEVER",
/**
* Eventually undoable.
*
* Use for updates which should not be captured immediately - likely
* exceptions which are part of some async multi-step process. Otherwise, all
* such updates would end up being captured with the next
* `CaptureUpdateAction.IMMEDIATELY` - triggered either by the next `updateScene`
* or internally by the editor.
*
* These updates will _eventually_ make it to the local undo / redo stacks.
*/
EVENTUALLY: "EVENTUALLY",
} as const;
export const EMBEDDABLE_THEME_FRONTMATTER_VALUES = ["light", "dark", "auto", "dafault"];
export const VIEW_TYPE_EXCALIDRAW = "excalidraw";
export const VIEW_TYPE_EXCALIDRAW_LOADING = "excalidraw-loading";

View File

@@ -412,7 +412,7 @@ export default class ExcalidrawPlugin extends Plugin {
try {
this.isReady = true;
switchToExcalidraw(this.app);
await switchToExcalidraw(this.app);
this.switchToExcalidarwAfterLoad();
} catch (e) {
new Notice("Error switching views to Excalidraw", 6000);

View File

@@ -166,6 +166,7 @@ export class CommandManager {
const fileMenuHandlerCreateNew = (menu: Menu, file: TFile) => {
menu.addItem((item: MenuItem) => {
item
.setSection('action-primary')
.setTitle(t("CREATE_NEW"))
.setIcon(ICON_NAME)
.onClick((e) => {createNewAction(e, file)});

View File

@@ -1,7 +1,7 @@
import { WorkspaceLeaf, TFile, Editor, MarkdownView, MarkdownFileInfo, MetadataCache, App, EventRef, Menu, FileView } from "obsidian";
import { ExcalidrawElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { getLink } from "../../utils/fileUtils";
import { editorInsertText, getExcalidrawViews, getParentOfClass, setExcalidrawView } from "../../utils/obsidianUtils";
import { editorInsertText, getExcalidrawViews, getParentOfClass, isUnwantedLeaf, setExcalidrawView } from "../../utils/obsidianUtils";
import ExcalidrawPlugin from "src/core/main";
import { DEBUGGING, debug } from "src/utils/debugHelper";
import { ExcalidrawAutomate } from "src/shared/ExcalidrawAutomate";
@@ -164,6 +164,13 @@ export class EventManager {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.onActiveLeafChangeHandler,`onActiveLeafChangeEventHandler`, leaf);
//https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/723
//In Obsidian 1.8.x the active excalidraw leaf is obscured by an empty leaf without a parent
//This hack resolves it
if(this.app.workspace.activeLeaf === leaf && isUnwantedLeaf(leaf)) {
leaf.detach();
return;
}
if (leaf.view && leaf.view.getViewType() === "pdf") {
this.plugin.lastPDFLeafID = leaf.id;
}

View File

@@ -9,6 +9,7 @@ declare var LZString: any;
let locale: Partial<typeof en> | null = null;
function loadLocale(lang: string): Partial<typeof en> {
if(lang === "zh") lang = "zh-cn"; //https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2247
if (Object.keys(PLUGIN_LANGUAGES).includes(lang)) {
const decompressed = LZString.decompressFromBase64(PLUGIN_LANGUAGES[lang]);
let x = {};

View File

@@ -33,7 +33,7 @@ export default {
DUPLICATE_IMAGE: "Duplicate selected image with a different image ID",
CONVERT_NOTE_TO_EXCALIDRAW: "Convert markdown note to Excalidraw Drawing",
CONVERT_EXCALIDRAW: "Convert *.excalidraw to *.md files",
CREATE_NEW: "Create new drawing",
CREATE_NEW: "New drawing",
CONVERT_FILE_KEEP_EXT: "*.excalidraw => *.excalidraw.md",
CONVERT_FILE_REPLACE_EXT: "*.excalidraw => *.md (Logseq compatibility)",
DOWNLOAD_LIBRARY: "Export stencil library as an *.excalidrawlib file",

View File

@@ -236,7 +236,7 @@ export default {
"在这种情况下,创建新绘图时将提示您选择使用哪个模板。<br>" +
"<b>专业提示:</b> 如果您正在使用 Obsidian Templater 插件,您可以将 Templater 代码添加到不同的" +
"Excalidraw 模板中,以自动配置您的绘图",
SCRIPT_FOLDER_NAME: "Excalidraw 自动化脚本的文件夹(大小写敏感",
SCRIPT_FOLDER_NAME: "Excalidraw 自动化脚本的文件夹(區分大小寫",
SCRIPT_FOLDER_DESC:
"此文件夹用于存放 Excalidraw 自动化脚本。" +
"您可以在 Obsidian 命令面板中执行这些脚本," +
@@ -722,6 +722,8 @@ FILENAME_HEAD: "文件名",
"更改此选项后,您可能需要重启 Obsidian 来使其生效。",
LATEX_DEFAULT_NAME: "插入 LaTeX 时的默认表达式",
LATEX_DEFAULT_DESC: "允许留空。允许使用类似 <code>\\color{white}</code> 的格式化表达式。",
LATEX_PREAMBLE_NAME : "LaTeX 前言文件(區分大小寫!)" ,
LATEX_PREAMBLE_DESC : "前言文件的完整路径,留空则使用默认值。如果文件不存在,此选项将被忽略。<br><strong>重要:</strong>更改后需要重新加载 Obsidian 才能生效!" ,
NONSTANDARD_HEAD: "非 Excalidraw.com 官方支持的特性",
NONSTANDARD_DESC: `这些特性不受 Excalidraw.com 官方支持。如果在 Excalidraw.com 导入绘图,这些特性将会发生不可预知的变化。
包括:自定义画笔工具的数量,自定义字体等。`,
@@ -1048,15 +1050,14 @@ EXPORTDIALOG_PAGE_SIZE : "页面大小",
EXPORTDIALOG_PAGE_ORIENTATION : "方向",
EXPORTDIALOG_ORIENTATION_PORTRAIT : "纵向",
EXPORTDIALOG_ORIENTATION_LANDSCAPE : "横向",
EXPORTDIALOG_PDF_DPI : "图像质量 [DPI]",
EXPORTDIALOG_PDF_FIT_TO_PAGE : "页面适配",
EXPORTDIALOG_PDF_FIT_OPTION : "适配页面",
EXPORTDIALOG_PDF_FIT_2_OPTION : "适配至 2 页" ,
EXPORTDIALOG_PDF_FIT_4_OPTION : "适配至 4 页" ,
EXPORTDIALOG_PDF_FIT_6_OPTION : "适配至 6 页" ,
EXPORTDIALOG_PDF_FIT_8_OPTION : "适配至 8 页" ,
EXPORTDIALOG_PDF_FIT_12_OPTION : "适配至 12 页" ,
EXPORTDIALOG_PDF_FIT_16_OPTION : "适配至 16 页" ,
EXPORTDIALOG_PDF_FIT_2_OPTION : "适配至最多 2 页" ,
EXPORTDIALOG_PDF_FIT_4_OPTION : "适配至最多 4 页" ,
EXPORTDIALOG_PDF_FIT_6_OPTION : "适配至最多 6 页" ,
EXPORTDIALOG_PDF_FIT_8_OPTION : "适配至最多 8 页" ,
EXPORTDIALOG_PDF_FIT_12_OPTION : "适配至最多 12 页" ,
EXPORTDIALOG_PDF_FIT_16_OPTION : "适配至最多 16 页" ,
EXPORTDIALOG_PDF_SCALE_OPTION : "使用图像缩放(可能跨多页)",
EXPORTDIALOG_PDF_PAPER_COLOR : "纸张颜色",
EXPORTDIALOG_PDF_PAPER_WHITE : "白色",
@@ -1064,6 +1065,8 @@ EXPORTDIALOG_PDF_PAPER_SCENE : "使用场景颜色",
EXPORTDIALOG_PDF_PAPER_CUSTOM : "自定义颜色",
EXPORTDIALOG_PDF_ALIGNMENT : "页面位置",
EXPORTDIALOG_PDF_ALIGN_CENTER : "居中",
EXPORTDIALOG_PDF_ALIGN_CENTER_LEFT : "左对齐居中" ,
EXPORTDIALOG_PDF_ALIGN_CENTER_RIGHT : "右对齐居中" ,
EXPORTDIALOG_PDF_ALIGN_TOP_LEFT : "左上角",
EXPORTDIALOG_PDF_ALIGN_TOP_CENTER : "顶部居中",
EXPORTDIALOG_PDF_ALIGN_TOP_RIGHT : "右上角",
@@ -1085,9 +1088,11 @@ EXPORTDIALOG_EXCALIDRAW : "Excalidraw",
EXPORTDIALOG_PNGTOCLIPBOARD : "PNG 复制到剪贴板",
EXPORTDIALOG_SVGTOCLIPBOARD : "SVG 复制到剪贴板",
EXPORTDIALOG_PDF : "导出 PDF 文件",
EXPORTDIALOG_PDFTOVAULT : "PDF 保存到 Vault",
EXPORTDIALOG_PDF_PROGRESS_NOTICE : "正在导出页面" ,
EXPORTDIALOG_PDF_PROGRESS_IMAGE : "的图像" ,
EXPORTDIALOG_PDF_PROGRESS_NOTICE : "正在导出 PDF。如果图像较大可能需要一些时间。" ,
EXPORTDIALOG_PDF_PROGRESS_DONE : "导出完成" ,
EXPORTDIALOG_PDF_PROGRESS_ERROR : "导出 PDF 时出错,请检查开发者控制台以获取详细信息" ,
// exportUtils.ts
PDF_EXPORT_DESKTOP_ONLY : "PDF 导出功能仅限桌面端使用" ,
};

View File

@@ -226,7 +226,7 @@ export class EmbeddableSettings extends Modal {
(async() => {
await this.ea.addElementsToView();
//@ts-ignore
this.ea.viewUpdateScene({appState: {}, storeAction: "update"});
this.ea.viewUpdateScene({appState: {}, captureUpdate: CaptureUpdateAction.NEVER});
this.close(); //close should only run once update scene is done
})();
} else {

View File

@@ -1,5 +1,6 @@
import { ExcalidrawAutomate } from "src/shared/ExcalidrawAutomate";
import { t } from "src/lang/helpers";
import { CaptureUpdateAction } from "src/constants/constants";
export const showFrameSettings = (ea: ExcalidrawAutomate) => {
const {enabled, clip, name, outline} = ea.getExcalidrawAPI().getAppState().frameRendering;
@@ -64,7 +65,7 @@ export const showFrameSettings = (ea: ExcalidrawAutomate) => {
appState: {
frameRendering: settings
},
storeAction: "update",
captureUpdate: CaptureUpdateAction.NEVER,
});
frameSettingsModal.close();
})

View File

@@ -17,6 +17,27 @@ 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.8.3":`
## Fixed
- Chinese translation not available since 2.8.0. [#2247](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2247)
- Since the most recent Samsung Android update, adding images from the gallery returns an Unsupported Image Type error. [#2245](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2245)
- Duplicating/removing frame while children selected [#9079](https://github.com/excalidraw/excalidraw/pull/9079)
`,
"2.8.2":`
## New
- Moved "Create new drawing" option up in the context menu [#2243](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2243)
## Fixed
- In rare cases drawing content gets overwritten with another drawing [#2152](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2152)
- "Wrap selection in frame" sets dark mode to light mode [#2240](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2240)
- Multiple bug fixes from Excalidraw.com
- Elbow arrows within boxes [#9077](https://github.com/excalidraw/excalidraw/issues/9077)
- Elbow arrow orthogonality [#9073](https://github.com/excalidraw/excalidraw/pull/9073)
- Improve library sidebar performance [#9060](https://github.com/excalidraw/excalidraw/pull/9060)
- Opacity slider now displays numerical value [#9009](https://github.com/excalidraw/excalidraw/pull/9009)
- Resize a frame and its children together when box selecting the frame and its children together [#9031](https://github.com/excalidraw/excalidraw/pull/9031)
- Excalidraw screen flickering in dark mode [#9057](https://github.com/excalidraw/excalidraw/pull/9057)
`,
"2.8.1":`
## Fixed
- Unable to open Excalidraw files after the 2.8.0 update. [#2235](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2235)
@@ -260,24 +281,5 @@ ${String.fromCharCode(96,96,96)}
- Hover-Editor compatibility resolved [2041](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2041)
- ${String.fromCharCode(96)}ExcalidrawAutomate.create() ${String.fromCharCode(96)} will now correctly include the markdown text in templates above Excalidraw Data and below YAML front matter. This also fixes the same issue with the **Deconstruct Selected Element script**.
`,
"2.6.7":`
Hoping to finally move on to 2.7.0... but still have one last bug to fix in 2.6.x!
## Fixed
I misread a line in the Excalidraw package code... ended up breaking image loading in 2.6.6. The icon library script didn't work right, and updating nested drawings caused all images in the scene to be dropped from memory. This led to image-placeholders in exports and broke copy-paste to Excalidraw.com and between drawings. I am surprised no one reported it! 😳
`,
"2.6.6":`
## Fixed
- Images and LaTeX formulas did not update in the scene when the source was changed until the Excalidraw drawing was closed and reopened. [#2105](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2105)
`,
"2.6.5":`
## Fixed
- Text sizing issue in the drawing that is first loaded after Obsidian restarts [#2086](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2086)
- Excalidraw didn't load if there was a file in the Excalidraw folder with a name that starts the same way as the Scripts folder name. [#2095](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2095)
- **OVERSIZED EXCALIDRAW TOOLBAR**: Added a new setting under "Excalidraw Appearance and Behavior > Theme and Styling" called "Limit Obsidian Font Size to Editor Text." This setting is off by default. When enabled, it restricts Obsidian's custom font size adjustments to editor text only, preventing unintended scaling of Excalidraw UI elements and other themes that rely on the default interface font size. Feel free to experiment with this setting to improve Excalidraw UI consistency. However, because this change affects the broader Obsidian UI, it's recommended to turn it off if any layout issues arise. [#2087](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/2087)`,
"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)
`,
};

View File

@@ -919,9 +919,9 @@ export const EXCALIDRAW_AUTOMATE_INFO: SuggesterInfo[] = [
},
{
field: "viewUpdateScene",
code: "viewUpdateScene(scene:{elements?:ExcalidrawElement[],appState?: AppState,files?: BinaryFileData,commitToHistory?: boolean,storeAction?: 'capture' | 'none' | 'update'},restore:boolean=false):void",
code: "viewUpdateScene(scene:{elements?:ExcalidrawElement[],appState?: AppState,files?: BinaryFileData,captureUpdate?: 'IMMEDIATELY' | 'NEVER' | 'EVENTUALLY'},restore:boolean=false):void",
desc: "Calls the ExcalidrawAPI updateScene function for the targetView. When restore=true, excalidraw will try to correct errors in the scene such as setting default values to missing element properties. " +
`Note that commitToHistory has been deprecated in Excalidraw and is no longer used. You should use storeAction instead. See ${hyperlink("https://github.com/excalidraw/excalidraw/pull/7898", "ExcalidrawAPI")} documentation for more information.`,
`Use captureUpdate to control undo/redo behavior: 'IMMEDIATELY' for immediate undoable updates (most local changes), 'NEVER' for updates that should never be undoable, or 'EVENTUALLY' for updates that should be undoable as part of an async multi-step process. See the ExcalidrawAPI documentation for more information.`,
after: "",
},
{

View File

@@ -46,7 +46,7 @@ import {
getWithBackground,
} from "src/utils/utils";
import { getAttachmentsFolderAndFilePath, getExcalidrawViews, getLeaf, getNewOrAdjacentLeaf, isObsidianThemeDark, mergeMarkdownFiles, openLeaf } from "src/utils/obsidianUtils";
import { AppState, BinaryFileData, DataURL, ExcalidrawImperativeAPI } from "@zsviczian/excalidraw/types/excalidraw/types";
import { AppState, BinaryFileData, DataURL, ExcalidrawImperativeAPI, SceneData } from "@zsviczian/excalidraw/types/excalidraw/types";
import { EmbeddedFile, EmbeddedFilesLoader } from "./EmbeddedFileLoader";
import { tex2dataURL } from "./LaTeX";
import { NewFileActions } from "src/shared/Dialogs/Prompt";
@@ -87,6 +87,7 @@ import { AddImageOptions, ImageInfo, SVGColorInfo } from "src/types/excalidrawAu
import { _measureText, cloneElement, createPNG, createSVG, errorMessage, filterColorMap, getEmbeddedFileForImageElment, getFontFamily, getLineBox, getTemplate, isColorStringTransparent, isSVGColorInfo, mergeColorMapIntoSVGColorInfo, normalizeLinePoints, repositionElementsToCursor, svgColorInfoToColorMap, updateOrAddSVGColorInfo, verifyMinimumPluginVersion } from "src/utils/excalidrawAutomateUtils";
import { exportToPDF, getMarginValue, getPageDimensions, PageDimensions, PageOrientation, PageSize, PDFExportScale, PDFPageProperties } from "src/utils/exportUtils";
import { FrameRenderingOptions } from "src/types/utilTypes";
import { CaptureUpdateAction } from "src/constants/constants";
extendPlugins([
HarmonyPlugin,
@@ -2237,7 +2238,7 @@ export class ExcalidrawAutomate {
this.targetView.updateScene({
elements: el.filter((e: ExcalidrawElement) => !ids.includes(e.id)),
appState: st,
storeAction: "capture",
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
});
//this.targetView.save();
return true;
@@ -2564,7 +2565,7 @@ export class ExcalidrawAutomate {
appState: {
viewModeEnabled: !isFullscreen,
},
storeAction: "update",
captureUpdate: CaptureUpdateAction.NEVER,
});
this.targetView.toolsPanelRef?.current?.setExcalidrawViewMode(!isFullscreen);
}
@@ -2586,7 +2587,7 @@ export class ExcalidrawAutomate {
return;
}
const view = this.targetView as ExcalidrawView;
view.updateScene({appState:{viewModeEnabled: enabled}, storeAction: "update"});
view.updateScene({appState:{viewModeEnabled: enabled}, captureUpdate: CaptureUpdateAction.NEVER});
view.toolsPanelRef?.current?.setExcalidrawViewMode(enabled);
}
@@ -2596,8 +2597,9 @@ export class ExcalidrawAutomate {
* @param {ExcalidrawElement[]} [scene.elements] - Array of elements in the scene.
* @param {AppState} [scene.appState] - The app state of the scene.
* @param {BinaryFileData} [scene.files] - The files in the scene.
* @param {boolean} [scene.commitToHistory] - Whether to commit the scene to history.
* @param {"capture" | "none" | "update"} [scene.storeAction] - The store action for the scene.
* @param {boolean} [scene.commitToHistory] - Whether to commit the scene to history. @deprecated Use scene.storageOption instead
* @param {"capture" | "none" | "update"} [scene.storeAction] - The store action for the scene. @deprecated Use scene.storageOption instead
* @param {"IMMEDIATELY" | "NEVER" | "EVENTUALLY"} [scene.captureUpdate] - The capture update action for the scene.
* @param {boolean} [restore=false] - Whether to restore legacy elements in the scene.
*/
viewUpdateScene (
@@ -2607,6 +2609,7 @@ export class ExcalidrawAutomate {
files?: BinaryFileData,
commitToHistory?: boolean,
storeAction?: "capture" | "none" | "update",
captureUpdate?: SceneData["captureUpdate"],
},
restore: boolean = false,
):void {
@@ -2623,6 +2626,7 @@ export class ExcalidrawAutomate {
appState: scene.appState,
files: scene.files,
storeAction: scene.storeAction,
captureUpdate: scene.captureUpdate,
},restore);
}
@@ -3308,7 +3312,7 @@ export class ExcalidrawAutomate {
elements.splice(newZIndex, 0, elements.splice(oldZIndex, 1)[0]);
this.targetView.updateScene({
elements,
storeAction: "capture",
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
});
};

View File

@@ -11,7 +11,7 @@ function createWorkerBlob(jsCode:string) {
const workerCode = `
var LZString=function(){var r=String.fromCharCode,o="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$",e={};function t(r,o){if(!e[r]){e[r]={};for(var n=0;n<r.length;n++)e[r][r.charAt(n)]=n}return e[r][o]}var i={compressToBase64:function(r){if(null==r)return"";var n=i._compress(r,6,function(r){return o.charAt(r)});switch(n.length%4){default:case 0:return n;case 1:return n+"===";case 2:return n+"==";case 3:return n+"="}},decompressFromBase64:function(r){return null==r?"":""==r?null:i._decompress(r.length,32,function(n){return t(o,r.charAt(n))})},compressToUTF16:function(o){return null==o?"":i._compress(o,15,function(o){return r(o+32)})+" "},decompressFromUTF16:function(r){return null==r?"":""==r?null:i._decompress(r.length,16384,function(o){return r.charCodeAt(o)-32})},compressToUint8Array:function(r){for(var o=i.compress(r),n=new Uint8Array(2*o.length),e=0,t=o.length;e<t;e++){var s=o.charCodeAt(e);n[2*e]=s>>>8,n[2*e+1]=s%256}return n},decompressFromUint8Array:function(o){if(null==o)return i.decompress(o);for(var n=new Array(o.length/2),e=0,t=n.length;e<t;e++)n[e]=256*o[2*e]+o[2*e+1];var s=[];return n.forEach(function(o){s.push(r(o))}),i.decompress(s.join(""))},compressToEncodedURIComponent:function(r){return null==r?"":i._compress(r,6,function(r){return n.charAt(r)})},decompressFromEncodedURIComponent:function(r){return null==r?"":""==r?null:(r=r.replace(/ /g,"+"),i._decompress(r.length,32,function(o){return t(n,r.charAt(o))}))},compress:function(o){return i._compress(o,16,function(o){return r(o)})},_compress:function(r,o,n){if(null==r)return"";var e,t,i,s={},u={},a="",p="",c="",l=2,f=3,h=2,d=[],m=0,v=0;for(i=0;i<r.length;i+=1)if(a=r.charAt(i),Object.prototype.hasOwnProperty.call(s,a)||(s[a]=f++,u[a]=!0),p=c+a,Object.prototype.hasOwnProperty.call(s,p))c=p;else{if(Object.prototype.hasOwnProperty.call(u,c)){if(c.charCodeAt(0)<256){for(e=0;e<h;e++)m<<=1,v==o-1?(v=0,d.push(n(m)),m=0):v++;for(t=c.charCodeAt(0),e=0;e<8;e++)m=m<<1|1&t,v==o-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}else{for(t=1,e=0;e<h;e++)m=m<<1|t,v==o-1?(v=0,d.push(n(m)),m=0):v++,t=0;for(t=c.charCodeAt(0),e=0;e<16;e++)m=m<<1|1&t,v==o-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}0==--l&&(l=Math.pow(2,h),h++),delete u[c]}else for(t=s[c],e=0;e<h;e++)m=m<<1|1&t,v==o-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;0==--l&&(l=Math.pow(2,h),h++),s[p]=f++,c=String(a)}if(""!==c){if(Object.prototype.hasOwnProperty.call(u,c)){if(c.charCodeAt(0)<256){for(e=0;e<h;e++)m<<=1,v==o-1?(v=0,d.push(n(m)),m=0):v++;for(t=c.charCodeAt(0),e=0;e<8;e++)m=m<<1|1&t,v==o-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}else{for(t=1,e=0;e<h;e++)m=m<<1|t,v==o-1?(v=0,d.push(n(m)),m=0):v++,t=0;for(t=c.charCodeAt(0),e=0;e<16;e++)m=m<<1|1&t,v==o-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}0==--l&&(l=Math.pow(2,h),h++),delete u[c]}else for(t=s[c],e=0;e<h;e++)m=m<<1|1&t,v==o-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;0==--l&&(l=Math.pow(2,h),h++)}for(t=2,e=0;e<h;e++)m=m<<1|1&t,v==o-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;for(;;){if(m<<=1,v==o-1){d.push(n(m));break}v++}return d.join("")},decompress:function(r){return null==r?"":""==r?null:i._decompress(r.length,32768,function(o){return r.charCodeAt(o)})},_decompress:function(o,n,e){var t,i,s,u,a,p,c,l=[],f=4,h=4,d=3,m="",v=[],g={val:e(0),position:n,index:1};for(t=0;t<3;t+=1)l[t]=t;for(s=0,a=Math.pow(2,2),p=1;p!=a;)u=g.val&g.position,g.position>>=1,0==g.position&&(g.position=n,g.val=e(g.index++)),s|=(u>0?1:0)*p,p<<=1;switch(s){case 0:for(s=0,a=Math.pow(2,8),p=1;p!=a;)u=g.val&g.position,g.position>>=1,0==g.position&&(g.position=n,g.val=e(g.index++)),s|=(u>0?1:0)*p,p<<=1;c=r(s);break;case 1:for(s=0,a=Math.pow(2,16),p=1;p!=a;)u=g.val&g.position,g.position>>=1,0==g.position&&(g.position=n,g.val=e(g.index++)),s|=(u>0?1:0)*p,p<<=1;c=r(s);break;case 2:return""}for(l[3]=c,i=c,v.push(c);;){if(g.index>o)return"";for(s=0,a=Math.pow(2,d),p=1;p!=a;)u=g.val&g.position,g.position>>=1,0==g.position&&(g.position=n,g.val=e(g.index++)),s|=(u>0?1:0)*p,p<<=1;switch(c=s){case 0:for(s=0,a=Math.pow(2,8),p=1;p!=a;)u=g.val&g.position,g.position>>=1,0==g.position&&(g.position=n,g.val=e(g.index++)),s|=(u>0?1:0)*p,p<<=1;l[h++]=r(s),c=h-1,f--;break;case 1:for(s=0,a=Math.pow(2,16),p=1;p!=a;)u=g.val&g.position,g.position>>=1,0==g.position&&(g.position=n,g.val=e(g.index++)),s|=(u>0?1:0)*p,p<<=1;l[h++]=r(s),c=h-1,f--;break;case 2:return v.join("")}if(0==f&&(f=Math.pow(2,d),d++),l[c])m=l[c];else{if(c!==h)return null;m=i+i.charAt(0)}v.push(m),l[h++]=i+m.charAt(0),i=m,0==--f&&(f=Math.pow(2,d),d++)}}};return i}();"function"==typeof define&&define.amd?define(function(){return LZString}):"undefined"!=typeof module&&null!=module?module.exports=LZString:"undefined"!=typeof angular&&null!=angular&&angular.module("LZString",[]).factory("LZString",function(){return LZString});
self.onmessage = function(e) {
const { data, action } = e.data;
const { data, action, messageId } = e.data;
try {
switch (action) {
case 'compress':
@@ -22,7 +22,7 @@ self.onmessage = function(e) {
for (let i = 0; i < compressed.length; i += chunkSize) {
result += compressed.slice(i, i + chunkSize) + '\\n\\n';
}
self.postMessage({ compressed: result.trim() });
self.postMessage({ messageId, compressed: result.trim() });
break;
case 'decompress':
if (!data) throw new Error("No input string provided for decompression.");
@@ -35,14 +35,13 @@ self.onmessage = function(e) {
}
}
const decompressed = LZString.decompressFromBase64(cleanedData);
self.postMessage({ decompressed });
self.postMessage({ messageId, decompressed });
break;
default:
throw new Error("Unknown action.");
}
} catch (error) {
// Post the error message back to the main thread
self.postMessage({ error: error.message });
self.postMessage({ messageId, error: error.message });
}
};
`;
@@ -55,27 +54,48 @@ export function initCompressionWorker() {
}
}
export async function runCompressionWorker(data:string, action: 'compress' | 'decompress'): Promise<string> {
let messageCounter = 0;
const pendingOperations = new Map<number, {
resolve: (value: string) => void,
reject: (reason: Error) => void
}>();
export async function runCompressionWorker(data: string, action: 'compress' | 'decompress'): Promise<string> {
const messageId = messageCounter++;
return new Promise((resolve, reject) => {
worker.onmessage = function(e) {
const { compressed, decompressed, error } = e.data;
if (error) {
reject(new Error(error));
} else if (compressed || decompressed) {
resolve(compressed || decompressed);
} else {
reject(new Error('Unexpected response from worker'));
}
};
// Store the promise handlers
pendingOperations.set(messageId, { resolve, reject });
// Set up the worker's error handler
worker.onerror = function(error) {
reject(new Error(error.message));
};
// Set up worker message handler if not already set
if (!worker.onmessage) {
worker.onmessage = function(e) {
const { messageId, compressed, decompressed, error } = e.data;
const handlers = pendingOperations.get(messageId);
if (handlers) {
if (error) {
handlers.reject(new Error(error));
} else if (compressed || decompressed) {
handlers.resolve(compressed || decompressed);
} else {
handlers.reject(new Error('Unexpected response from worker'));
}
pendingOperations.delete(messageId);
}
};
// Post the message to the worker
worker.postMessage({ data, action });
worker.onerror = function(error) {
// Handle any pending operations in case of worker error
for (const [id, handlers] of pendingOperations) {
handlers.reject(new Error(error.message));
pendingOperations.delete(id);
}
};
}
// Post message with ID
worker.postMessage({ messageId, data, action });
});
}

View File

@@ -7,6 +7,7 @@ import { cloneElement } from "./excalidrawAutomateUtils";
import { ExcalidrawFrameElement } from "@zsviczian/excalidraw/types/excalidraw/element/types";
import { addAppendUpdateCustomData } from "./utils";
import { mutateElement } from "src/constants/constants";
import { CaptureUpdateAction } from "src/constants/constants";
export const setDynamicStyle = (
ea: ExcalidrawAutomate,
@@ -17,7 +18,7 @@ export const setDynamicStyle = (
) => {
if(dynamicStyle === "none") {
view.excalidrawContainer?.removeAttribute("style");
setTimeout(()=>view.updateScene({appState:{dynamicStyle: ""}, storeAction: "update"}));
setTimeout(()=>view.updateScene({appState:{dynamicStyle: ""}, captureUpdate: CaptureUpdateAction.NEVER}));
const toolspanel = view.toolsPanelRef?.current?.containerRef?.current;
if(toolspanel) {
let toolsStyle = toolspanel.getAttribute("style");
@@ -178,7 +179,7 @@ export const setDynamicStyle = (
frameColor,
dynamicStyle: styleObject
},
storeAction: "update",
captureUpdate: CaptureUpdateAction.NEVER,
});
view = null;
ea = null;

View File

@@ -14,6 +14,7 @@ import { nanoid } from "nanoid";
import { t } from "src/lang/helpers";
import { Mutable } from "@zsviczian/excalidraw/types/excalidraw/utility-types";
import { EmbeddedFile } from "src/shared/EmbeddedFileLoader";
import { CaptureUpdateAction } from "src/constants/constants";
export async function insertImageToView(
ea: ExcalidrawAutomate,
@@ -264,7 +265,7 @@ export async function addBackOfTheNoteCard(
api.selectElements([el]);
if(activate) {
window.setTimeout(()=>{
api.updateScene({appState: {activeEmbeddable: {element: el, state: "active"}}, storeAction: "update"});
api.updateScene({appState: {activeEmbeddable: {element: el, state: "active"}}, captureUpdate: CaptureUpdateAction.NEVER,});
if(found) view.getEmbeddableLeafElementById(el.id)?.editNode?.();
});
}

View File

@@ -8,7 +8,7 @@ import {
import ExcalidrawPlugin from "../core/main";
import { checkAndCreateFolder, splitFolderAndFilename } from "./fileUtils";
import { linkClickModifierType, ModifierKeys } from "./modifierkeyHelper";
import { EXCALIDRAW_PLUGIN, REG_BLOCK_REF_CLEAN, REG_SECTION_REF_CLEAN, VIEW_TYPE_EXCALIDRAW } from "src/constants/constants";
import { DEVICE, EXCALIDRAW_PLUGIN, REG_BLOCK_REF_CLEAN, REG_SECTION_REF_CLEAN, VIEW_TYPE_EXCALIDRAW } from "src/constants/constants";
import yaml from "js-yaml";
import { debug, DEBUGGING } from "./debugHelper";
import ExcalidrawView from "src/view/ExcalidrawView";
@@ -416,3 +416,12 @@ export async function closeLeafView(leaf: WorkspaceLeaf) {
state: {},
});
}
//In Obsidian 1.8.x the active excalidraw leaf is obscured by an empty leaf without a parent
//In some ways similar to patchMobileView() - though does something completely different, but both mobile leaf related
export function isUnwantedLeaf(leaf:WorkspaceLeaf):boolean {
return !DEVICE.isDesktop &&
leaf.view?.getViewType() === "empty" && leaf.parent && !leaf.parent.parent &&
//@ts-ignore
leaf.parent.type === "split" && leaf.parent.children.length === 1
}

View File

@@ -1,17 +1,19 @@
import { App, FileView, WorkspaceLeaf } from "obsidian";
import { VIEW_TYPE_EXCALIDRAW_LOADING } from "src/constants/constants";
import { act } from "react";
import { DEVICE, VIEW_TYPE_EXCALIDRAW_LOADING } from "src/constants/constants";
import ExcalidrawPlugin from "src/core/main";
import { setExcalidrawView } from "src/utils/obsidianUtils";
import { isUnwantedLeaf, setExcalidrawView } from "src/utils/obsidianUtils";
export function switchToExcalidraw(app: App) {
const leaves = app.workspace.getLeavesOfType(VIEW_TYPE_EXCALIDRAW_LOADING).filter(l=>l.view instanceof ExcalidrawLoading);
leaves.forEach(l=>(l.view as ExcalidrawLoading).switchToeExcalidraw());
export async function switchToExcalidraw(app: App) {
const leaves = app.workspace.getLeavesOfType(VIEW_TYPE_EXCALIDRAW_LOADING);
for(const leaf of leaves) {
await (leaf.view as ExcalidrawLoading)?.switchToeExcalidraw();
}
}
export class ExcalidrawLoading extends FileView {
constructor(leaf: WorkspaceLeaf, private plugin: ExcalidrawPlugin) {
super(leaf);
this.displayLoadingText();
}
public onload() {
@@ -19,8 +21,13 @@ export class ExcalidrawLoading extends FileView {
this.displayLoadingText();
}
public switchToeExcalidraw() {
setExcalidrawView(this.leaf);
public async switchToeExcalidraw() {
const prevLeaf = this.app.workspace.activeLeaf;
await setExcalidrawView(this.leaf);
const activeLeaf = this.app.workspace.activeLeaf;
if(prevLeaf === this.leaf && activeLeaf !== prevLeaf && isUnwantedLeaf(activeLeaf)) {
this.app.workspace.activeLeaf.detach();
}
}
getViewType(): string {

View File

@@ -30,6 +30,7 @@ import {
ExcalidrawImperativeAPI,
Gesture,
LibraryItems,
SceneData,
UIAppState,
} from "@zsviczian/excalidraw/types/excalidraw/types";
import {
@@ -152,8 +153,8 @@ import { Position, ViewSemaphores } from "../types/excalidrawViewTypes";
import { DropManager } from "./managers/DropManager";
import { ImageInfo } from "src/types/excalidrawAutomateTypes";
import { exportToPDF, getMarginValue, getPageDimensions, PageOrientation, PageSize } from "src/utils/exportUtils";
import { create } from "domain";
import { FrameRenderingOptions } from "src/types/utilTypes";
import { CaptureUpdateAction } from "src/constants/constants";
const EMBEDDABLE_SEMAPHORE_TIMEOUT = 2000;
const PREVENT_RELOAD_TIMEOUT = 2000;
@@ -253,7 +254,7 @@ export const addFiles = async (
view.updateScene({
elements: s.scene.elements,
appState: s.scene.appState,
storeAction: "update",
captureUpdate: CaptureUpdateAction.NEVER,
});
}
for (const f of files) {
@@ -1096,21 +1097,21 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
toggleDisableBinding() {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.toggleDisableBinding, "ExcalidrawView.toggleDisableBinding");
const newState = !this.excalidrawAPI.getAppState().invertBindingBehaviour;
this.updateScene({appState: {invertBindingBehaviour:newState}, storeAction: "update"});
this.updateScene({appState: {invertBindingBehaviour:newState}, captureUpdate: CaptureUpdateAction.NEVER,});
new Notice(newState ? t("ARROW_BINDING_INVERSE_MODE") : t("ARROW_BINDING_NORMAL_MODE"));
}
toggleFrameRendering() {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.toggleFrameRendering, "ExcalidrawView.toggleFrameRendering");
const frameRenderingSt = (this.excalidrawAPI as ExcalidrawImperativeAPI).getAppState().frameRendering;
this.updateScene({appState: {frameRendering: {...frameRenderingSt, enabled: !frameRenderingSt.enabled}}, storeAction: "update"});
this.updateScene({appState: {frameRendering: {...frameRenderingSt, enabled: !frameRenderingSt.enabled}}, captureUpdate: CaptureUpdateAction.NEVER,});
new Notice(frameRenderingSt.enabled ? t("FRAME_CLIPPING_ENABLED") : t("FRAME_CLIPPING_DISABLED"));
}
toggleFrameClipping() {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.toggleFrameClipping, "ExcalidrawView.toggleFrameClipping");
const frameRenderingSt = (this.excalidrawAPI as ExcalidrawImperativeAPI).getAppState().frameRendering;
this.updateScene({appState: {frameRendering: {...frameRenderingSt, clip: !frameRenderingSt.clip}}, storeAction: "update"});
this.updateScene({appState: {frameRendering: {...frameRenderingSt, clip: !frameRenderingSt.clip}}, captureUpdate: CaptureUpdateAction.NEVER,});
new Notice(frameRenderingSt.clip ? "Frame Clipping: Enabled" : "Frame Clipping: Disabled");
}
@@ -1379,7 +1380,7 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
if (this.excalidrawData.hasMermaid(selectedImage.fileId) || getMermaidText(imageElement)) {
if(shouldRenderMermaid) {
const api = this.excalidrawAPI as ExcalidrawImperativeAPI;
api.updateScene({appState: {openDialog: { name: "ttd", tab: "mermaid" }}, storeAction: "update"})
api.updateScene({appState: {openDialog: { name: "ttd", tab: "mermaid" }}, captureUpdate: CaptureUpdateAction.NEVER })
}
return;
}
@@ -1806,7 +1807,7 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
...st,
theme,
},
storeAction: "update",
captureUpdate: CaptureUpdateAction.NEVER,
});
}
@@ -1976,6 +1977,11 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
protected async onClose(): Promise<void> {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.onClose,`ExcalidrawView.onClose, file:${this.file?.name}`);
//I noticed Obsidian calls this function twice when disabling the plugin
//once from "unregisterView"
//the from "detachLeavesOfType"
if(!this.dropManager) return; //the view is already closed
// This happens when the user right clicks a tab and selects delete
// in this case the onDelete event handler tirggers, but then Obsidian's delete event handler reaches onclose first, and
// when the function is called a second time via on delete an error is thrown.)
@@ -2741,7 +2747,7 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
{
elements: excalidrawData.elements.concat(deletedElements??[]), //need to preserve deleted elements during autosave if images, links, etc. are updated
files: excalidrawData.files,
storeAction: justloaded ? "update" : "update", //was none, but I think based on a false understanding of none
captureUpdate: CaptureUpdateAction.NEVER,
},
justloaded
);
@@ -2764,7 +2770,7 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
pinnedScripts: this.plugin.settings.pinnedScripts,
customPens: this.plugin.settings.customPens.slice(0,this.plugin.settings.numberOfCustomPens),
},
storeAction: justloaded ? "update" : "update", //was none, but I think based on a false understanding of none
captureUpdate: CaptureUpdateAction.NEVER,
},
);
if (
@@ -3530,7 +3536,7 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
this.updateScene(
{
elements,
storeAction: "capture",
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
},
shouldRestoreElements,
);
@@ -3930,7 +3936,7 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
st = (this.excalidrawAPI as ExcalidrawImperativeAPI).getAppState();
canvasColor = canvasColor ?? st.viewBackgroundColor === "transparent" ? "white" : st.viewBackgroundColor;
}
window.setTimeout(()=>this.updateScene({appState:{gridColor: this.getGridColor(canvasColor, st)}, storeAction: "update"}));
window.setTimeout(()=>this.updateScene({appState:{gridColor: this.getGridColor(canvasColor, st)}, captureUpdate: CaptureUpdateAction.NEVER}));
}
private canvasColorChangeHook(st: AppState) {
@@ -4183,7 +4189,7 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
this.excalidrawData.deleteTextElement(clone.id);
sceneElements[sceneElements.indexOf(el)] = clone;
}
this.updateScene({elements: sceneElements, storeAction: "update"});
this.updateScene({elements: sceneElements, captureUpdate: CaptureUpdateAction.NEVER});
//then insert images and embeds
//shift text elements down to make space for images and embeds
@@ -4307,7 +4313,7 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
clone.rawText = WARNING;
elements[elements.indexOf(el[0])] = clone;
this.excalidrawData.setTextElement(clone.id,WARNING,()=>{});
this.updateScene({elements, storeAction: "update"});
this.updateScene({elements, captureUpdate: CaptureUpdateAction.NEVER});
api.history.clear();
}
});
@@ -4331,7 +4337,7 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
clone.isDeleted = true;
this.excalidrawData.deleteTextElement(clone.id);
elements[elements.indexOf(el[0])] = clone;
this.updateScene({elements, storeAction: "update"});
this.updateScene({elements, captureUpdate: CaptureUpdateAction.NEVER});
const ea:ExcalidrawAutomate = getEA(this);
if(IMAGE_TYPES.contains(file.extension)) {
ea.selectElementsInView([await insertImageToView (ea, center, file)]);
@@ -4384,7 +4390,7 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
}
elements[elements.indexOf(el[0])] = clone;
this.updateScene({elements, storeAction: "update"});
this.updateScene({elements, captureUpdate: CaptureUpdateAction.NEVER});
if(clone.containerId) this.updateContainerSize(clone.containerId);
this.setDirty(8.1);
}
@@ -5600,7 +5606,7 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
}
api.updateScene({
appState: { pinnedScripts: this.plugin.settings.pinnedScripts },
storeAction: "update",
captureUpdate: CaptureUpdateAction.NEVER,
});
}
@@ -5614,7 +5620,7 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
appState: {
customPens: this.plugin.settings.customPens.slice(0,this.plugin.settings.numberOfCustomPens),
},
storeAction: "update",
captureUpdate: CaptureUpdateAction.NEVER,
});
}
@@ -5626,7 +5632,7 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
}
api.updateScene({
appState: { allowPinchZoom: this.plugin.settings.allowPinchZoom },
storeAction: "update",
captureUpdate: CaptureUpdateAction.NEVER,
});
}
@@ -5638,7 +5644,7 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
}
api.updateScene({
appState: { allowWheelZoom: this.plugin.settings.allowWheelZoom },
storeAction: "update",
captureUpdate: CaptureUpdateAction.NEVER,
});
}
@@ -5651,7 +5657,7 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
const st = api.getAppState();
api.updateScene({
appState: { trayModeEnabled: !st.trayModeEnabled },
storeAction: "update",
captureUpdate: CaptureUpdateAction.NEVER,
});
//just in case settings were updated via Obsidian sync
@@ -5899,14 +5905,29 @@ export default class ExcalidrawView extends TextFileView implements HoverParent{
appState?: any;
files?: any;
storeAction?: "capture" | "none" | "update"; //https://github.com/excalidraw/excalidraw/pull/7898
captureUpdate?: SceneData["captureUpdate"];
},
shouldRestore: boolean = false,
) {
(process.env.NODE_ENV === 'development') && DEBUGGING && debug(this.updateScene, "ExcalidrawView.updateScene", scene, shouldRestore);
const api = this.excalidrawAPI;
const api = this.excalidrawAPI as ExcalidrawImperativeAPI;
if (!api) {
return;
}
if(typeof scene.storeAction === "string") {
switch(scene.storeAction) {
case "capture":
scene.captureUpdate = CaptureUpdateAction.IMMEDIATELY;
break;
case "none":
scene.captureUpdate = CaptureUpdateAction.EVENTUALLY;
break;
default:
scene.captureUpdate = CaptureUpdateAction.NEVER;
}
delete scene.storeAction;
}
const shouldRestoreElements = scene.elements && shouldRestore;
if (shouldRestoreElements) {
scene.elements = restore(scene, null, null).elements;

View File

@@ -15,6 +15,7 @@ import { EmbeddableSettings } from "src/shared/Dialogs/EmbeddableSettings";
import { openExternalLink } from "src/utils/excalidrawViewUtils";
import { getEA } from "src/core";
import { ExcalidrawAutomate } from "src/shared/ExcalidrawAutomate";
import { CaptureUpdateAction } from "src/constants/constants";
export class EmbeddableMenu {
private menuFadeTimeout: number = 0;
@@ -70,7 +71,7 @@ export class EmbeddableMenu {
};
private async actionMarkdownSelection (file: TFile, isExcalidrawFile: boolean, subpath: string, element: ExcalidrawEmbeddableElement) {
this.view.updateScene({appState: {activeEmbeddable: null}, storeAction: "update"});
this.view.updateScene({appState: {activeEmbeddable: null}, captureUpdate: CaptureUpdateAction.NEVER});
const sections = (await this.view.app.metadataCache.blockCache
.getForFile({ isCancelled: () => false },file))
.blocks.filter((b: any) => b.display && b.node?.type === "heading")
@@ -98,7 +99,7 @@ export class EmbeddableMenu {
private async actionMarkdownBlock (file: TFile, subpath: string, element: ExcalidrawEmbeddableElement) {
if(!file) return;
this.view.updateScene({appState: {activeEmbeddable: null}, storeAction: "update"});
this.view.updateScene({appState: {activeEmbeddable: null}, captureUpdate: CaptureUpdateAction.NEVER});
const paragraphs = (await this.view.app.metadataCache.blockCache
.getForFile({ isCancelled: () => false },file))
.blocks.filter((b: any) => b.display && b.node &&

View File

@@ -12,6 +12,7 @@ import { ICONS, penIcon, stringToSVG } from "../../../constants/actionIcons";
import { UniversalInsertFileModal } from "src/shared/Dialogs/UniversalInsertFileModal";
import { t } from "src/lang/helpers";
import { getExcalidrawViews } from "src/utils/obsidianUtils";
import { CaptureUpdateAction } from "src/constants/constants";
export function setPen (pen: PenStyle, api: any) {
const st = api.getAppState();
@@ -34,7 +35,7 @@ export function setPen (pen: PenStyle, api: any) {
}}
: null,
},
storeAction: "update",
captureUpdate: CaptureUpdateAction.NEVER,
})
}
@@ -51,7 +52,7 @@ export function resetStrokeOptions (resetCustomPen:any, api: ExcalidrawImperativ
resetCustomPen: null,
...clearCurrentStrokeOptions ? {currentStrokeOptions: null} : null,
},
storeAction: "update",
captureUpdate: CaptureUpdateAction.NEVER
});
}

View File

@@ -684,6 +684,10 @@ export class ToolsPanel extends React.Component<PanelProps, PanelState> {
return "";
}
if(!this.view.plugin._loaded) {
return null;
}
const downloadedScriptsRoot = `${this.view.plugin.settings.scriptFolderPath}/${SCRIPT_INSTALL_FOLDER}/`;
const filterCondition = (key: string): boolean =>