You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Lets a script ask to be automatically re-run every time a new Excalidraw
view opens. First call prompts the user Allow/Deny/Ask-me-later via the
existing MultiOptionConfirmationPrompt; the decision persists in the new
autostartScripts setting, a sibling of scriptEngineSettings since it is
plugin/user-trusted permission state a script must not silently flip.
Two additions from user testing: a fresh "allow" also immediately re-runs
the script in every other currently-open view (ScriptEngine.
attachAutostartScriptToOpenViews()), not only views opened afterward; and
renaming/deleting a script's file now purges its autostartScripts entry
(ScriptEngine.purgeAutostartPermission(), wired into the existing
delete/rename event handlers) instead of leaving a stale orphaned
permission under the old name.
No autostart-on-view-open execution or settings UI yet - that's next.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: RefactorPlan.md
+2-1Lines changed: 2 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1237,7 +1237,7 @@ action reusing the same rendering component (matching how
1237
1237
| --- | --- | --- |
1238
1238
| 1. Type move | Complete | Moved `SelectedElementMenuAction`/`SelectedElementMenuProvider` from `SelectedElementActionsMenu.ts` to new `src/types/elementActionTypes.ts`. Pure mechanical move, no other file referenced the old location yet, so no compatibility re-export was needed. |
1239
1239
| 2. `registerElementActionProvider` | Implemented; user-tested, one fix applied | Added the public method on `ExcalidrawAutomate` (delegates to the existing `view.selectedElementActionsMenu.registerProvider()`, id defaults to `this.activeScript ?? nanoid()`, matching `createSidepanelTab`'s precedent). Added `ScriptEngine.trackElementActionProvider()`/cleanup in `unloadScript()` (`src/shared/Scripts.ts`) for the one gap the existing mechanism didn't already cover: a script's file being deleted while a view using its registered action is still open (ordinary view-close cleanup was already handled by `SelectedElementActionsMenu.destroy()`). Added the `SuggesterInfo.ts` entry and a `## New` bullet in `Messages.ts` under `2.27.0` per the ExcalidrawAutomate Change Checklist. No new locale keys needed — this API produces no plugin-authored user-visible strings (button text/icon come from the registering script). User tested registering multiple menus and clearing them independently — both worked. Found and fixed one bug: `registerProvider()` primes the menu to recompute on its *next* `update()` call (by resetting `selectedElementId`), but nothing was triggering `update()` immediately — if an eligible element was already selected when a script registered (e.g. run via command palette), the button didn't appear until the user deselected and reselected. Fixed by having `registerElementActionProvider()` immediately call `selectedElementActionsMenu.update(view.getViewElements(), appState)` right after registering, mirroring the exact call `ExcalidrawRoot.ts`'s mount effect already makes at view-open time. |
1240
-
| 3. Autostart data + prompt flow | Not started ||
1240
+
| 3. Autostart data + prompt flow | Implemented; pending user testing | Added `autostartScripts: { [scriptName: string]: "allow" \| "deny" \| "unknown" }` (default `{}`) to `ExcalidrawSettings`/`DEFAULT_SETTINGS` (`src/core/settingsDefaults.ts`) — deliberately a sibling of `scriptEngineSettings`, not reused, since this is plugin/user-trusted permission state a script must not silently flip. Added `ExcalidrawAutomate.registerAutostart(): Promise<"allow"\|"deny"\|"pending">` reusing the existing `MultiOptionConfirmationPrompt<T>` (`src/shared/Dialogs/Prompt.ts`, same class `MarkdownImageController.ts` already uses for its keep/delete prompt): no active script → `errorMessage()` + `"pending"`; missing entry → created as `"unknown"` and persisted immediately (visible in the future management UI right after the first run, before any button is clicked); `"allow"`/`"deny"` short-circuit with no prompt; `"unknown"` (including a dismissed-without-choosing prompt, which the class resolves as `null`) shows the Allow/Deny/Ask-me-later prompt, persists Allow/Deny, and leaves `"unknown"`+returns `"pending"` for Ask-me-later or dismissal. Added `SuggesterInfo.ts` entry, a `## New` bullet in `Messages.ts` under `2.27.0`, and new locale keys (`AUTOSTART_SCRIPT_PROMPT`/`_ALLOW`/`_DENY`/`_ASK_LATER`) in `en.ts` + `ru`/`es`/`zh-cn`/`zh-tw` — this step's prompt text and button labels are genuinely new plugin-authored user-visible strings, unlike step 2. Two scope additions made after initial user testing, both confirmed via `AskUserQuestion` before implementing: (a) a fresh "allow" now also immediately re-runs the script in every other currently-open Excalidraw view via new `ScriptEngine.attachAutostartScriptToOpenViews()` (enumerates `getExcalidrawViews(app, true)`, reuses `executeScript()` per view, per-view try/catch so one failure doesn't affect others) — otherwise approval only ever affected views opened afterward; (b) deleting or renaming a script's file now purges its `autostartScripts` entry via new `ScriptEngine.purgeAutostartPermission()`, called from the existing `deleteEventHandler`/`renameEventHandler` (not from `unloadScript()` itself, since that method is also called for non-identity-changing cases like a script-folder-path change or plugin unload, where purging would be wrong) — a renamed script now starts fresh under its new name instead of leaving a stale orphaned entry under the old one forever. No autostart-on-view-open execution/UI wiring yet (steps 4-5). |
1241
1241
| 4. Autostart execution | Not started ||
1242
1242
| 5. Autostart UI | Not started ||
1243
1243
@@ -1246,3 +1246,4 @@ action reusing the same rendering component (matching how
1246
1246
| Date | Action | Outcome | Validation |
1247
1247
| --- | --- | --- | --- |
1248
1248
| 2026-08-14 | Completed steps 1-2 | See Progress table above |`npm run build`, `tsc --noEmit`, `npm run lib` (public API surface touched) all passed; `node --check dist/main.js` passed; ESLint unchanged at 470/0 across the whole repo (same baseline before and after via `git stash` comparison); the existing 33-warning circular-dependency baseline is unchanged. Manual validation pending: register an action from a throwaway script, confirm it appears/disappears correctly across selection changes, and confirm deleting the script file while its view is open removes the button with no error on the next selection change. |
1249
+
| 2026-08-14 | Completed step 3 (including two scope additions from user testing feedback — see Progress table) | See Progress table above | `npm run build`, `tsc --noEmit` (no new errors in touched files; remaining errors are pre-existing environment/`node_modules` typing issues), `npm run lib` (public API surface touched) all passed; `node --check dist/main.js` passed; ESLint on touched files plus full-repo run both unchanged at the 470-problem baseline (0 new errors — one transient `no-unsafe-assignment` on an untyped `catch (e)` was introduced and fixed immediately by typing it `catch (error: unknown)`, matching the existing pattern already used elsewhere in `Scripts.ts`). Manual validation pending: run a script calling `registerAutostart()` twice — first run must prompt, second must not (state persisted); choose "Ask me later" and confirm it prompts again next run; confirm the entry appears in `settings.autostartScripts` immediately after the first call, before any button is clicked; with a second Excalidraw view already open, confirm clicking Allow attaches the script to that other view immediately; rename the script file and confirm its old `autostartScripts` entry is purged and the new name prompts fresh. |
Copy file name to clipboardExpand all lines: src/lang/locale/en.ts
+5Lines changed: 5 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -1220,6 +1220,11 @@ export default {
1220
1220
"If enabled, Excalidraw will execute file-level <code>excalidraw-onload-script</code> code in all drawings you open from now on, until you disable this setting. "+
1221
1221
"This creates a risk if you download markdown files from unknown sources: a malicious actor can use <code>excalidraw-onload-script</code> "+
1222
1222
"to run any command in Obsidian and potentially transfer data to the internet. Only enable this if you trust the file and its source.",
1223
+
AUTOSTART_SCRIPT_PROMPT:
1224
+
"wants to run automatically every time you open an Excalidraw drawing. Do you want to allow this?",
Copy file name to clipboardExpand all lines: src/lang/locale/es.ts
+5Lines changed: 5 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -1185,6 +1185,11 @@ export default {
1185
1185
"Si está habilitado, Excalidraw ejecutará el <code>excalidraw-onload-script</code> a nivel de archivo en todos los dibujos que abras a partir de ahora, hasta que desactives esta opción. "+
1186
1186
"Esto crea un riesgo si descargas archivos Markdown de fuentes desconocidas: un actor malicioso puede usar <code>excalidraw-onload-script</code> "+
1187
1187
"para ejecutar cualquier comando en Obsidian y potencialmente transferir datos a internet. Actívalo solo si confías en el archivo y en su origen.",
1188
+
AUTOSTART_SCRIPT_PROMPT:
1189
+
"quiere ejecutarse automáticamente cada vez que abras un dibujo de Excalidraw. ¿Deseas permitirlo?",
1190
+
AUTOSTART_SCRIPT_ALLOW: "Permitir",
1191
+
AUTOSTART_SCRIPT_DENY: "Denegar",
1192
+
AUTOSTART_SCRIPT_ASK_LATER: "Preguntar más tarde",
1188
1193
ENABLE_COMMAND_LINKS_NAME: "Habilitar enlaces de comandos (cmd://)",
1189
1194
ENABLE_COMMAND_LINKS_CONFIRMATION:
1190
1195
"Este enlace ejecuta un comando de Obsidian mediante <code>cmd://</code>. ¿Quieres habilitar los enlaces de comandos?",
Copy file name to clipboardExpand all lines: src/lang/locale/ru.ts
+5Lines changed: 5 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -1090,6 +1090,11 @@ export default {
1090
1090
"Если эта настройка включена, Excalidraw будет выполнять <code>excalidraw-onload-script</code> на уровне файла во всех рисунках, которые вы откроете далее, пока вы не отключите эту настройку. "+
1091
1091
"Это создаёт риск, если вы загружаете Markdown-файлы из неизвестных источников: злоумышленник может использовать <code>excalidraw-onload-script</code> "+
1092
1092
"для запуска любой команды в Obsidian и потенциальной передачи данных в интернет. Включайте это только если доверяете файлу и его источнику.",
1093
+
AUTOSTART_SCRIPT_PROMPT:
1094
+
"хочет запускаться автоматически каждый раз, когда вы открываете рисунок Excalidraw. Разрешить это?",
- Scripts can now ask to be automatically re-run every time a new Excalidraw view is opened, with a user-confirmed Allow/Deny/Ask-me-later prompt; a fresh Allow also attaches the script to every other currently-open view immediately. Manage which scripts are allowed to autostart from the "Autostart scripts" command or the Compatibility settings section:
- Refactoring the plugin. Removed unused functions, improved code structure and readability. Removed the obsolete Draw.io/Diagram plugin integration (since the other plugin no longer works and is not maintained) and retired the Create DrawIO file script from the script library.
"Requests permission for this script to be automatically re-run every time a new Excalidraw view is opened. "+
1015
+
"The first time a given script calls this, the user is prompted to Allow, Deny, or decide later; the decision persists and is not asked again unless the user changes it (via the \"Autostart scripts\" command or settings section) or previously picked \"Ask me later\". "+
1016
+
"A fresh Allow also immediately re-runs the script in every other currently-open Excalidraw view, so it attaches everywhere right away instead of only the next time each view is opened. "+
1017
+
'Returns "allow", "deny", or "pending" (no active script, or the user has not yet decided). Typically called near the top of a script, guarding whatever the script wants to re-register on autostart, e.g. registerElementActionProvider().',
0 commit comments