mirror of
https://github.com/zsviczian/obsidian-excalidraw-plugin.git
synced 2025-08-06 05:46:28 +00:00
Compare commits
6 Commits
2.4.0-beta
...
hotkey-ove
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c949dc71c | ||
|
|
0439d67a0c | ||
|
|
d3446a20b1 | ||
|
|
5b37dc2e38 | ||
|
|
eee264918e | ||
|
|
89172a88f1 |
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "obsidian-excalidraw-plugin",
|
||||
"name": "Excalidraw",
|
||||
"version": "2.4.0-beta-10",
|
||||
"version": "2.4.0-rc-1",
|
||||
"minAppVersion": "1.1.6",
|
||||
"description": "An Obsidian plugin to edit and view Excalidraw drawings",
|
||||
"author": "Zsolt Viczian",
|
||||
|
||||
22
package.json
22
package.json
@@ -24,23 +24,27 @@
|
||||
"clsx": "^2.0.0",
|
||||
"colormaster": "^1.2.1",
|
||||
"gl-matrix": "^3.4.3",
|
||||
"js-yaml": "^4.1.0",
|
||||
"lucide-react": "^0.263.1",
|
||||
"mathjax-full": "^3.2.2",
|
||||
"monkey-around": "^2.3.0",
|
||||
"nanoid": "^4.0.2",
|
||||
"opentype.js": "^1.3.4",
|
||||
"polybooljs": "^1.2.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"roughjs": "^4.5.2",
|
||||
"js-yaml": "^4.1.0",
|
||||
"opentype.js": "^1.3.4",
|
||||
"woff2sfnt-sfnt2woff": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"dotenv": "^16.4.5",
|
||||
"@babel/core": "^7.22.9",
|
||||
"@babel/preset-env": "^7.22.10",
|
||||
"@babel/preset-react": "^7.22.5",
|
||||
"@codemirror/commands": "^6.3.3",
|
||||
"@codemirror/language": "^6.10.0",
|
||||
"@codemirror/search": "^6.5.5",
|
||||
"@codemirror/state": "^6.4.0",
|
||||
"@codemirror/view": "^6.23.0",
|
||||
"@excalidraw/eslint-config": "^1.0.3",
|
||||
"@excalidraw/prettier-config": "^1.0.2",
|
||||
"@rollup/plugin-babel": "^6.0.3",
|
||||
@@ -50,14 +54,15 @@
|
||||
"@rollup/plugin-typescript": "^11.1.6",
|
||||
"@types/chroma-js": "^2.4.0",
|
||||
"@types/js-beautify": "^1.14.0",
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"@types/node": "^20.10.5",
|
||||
"@types/opentype.js": "^1.3.8",
|
||||
"@types/react": "^18.2.45",
|
||||
"@types/react-dom": "^18.2.18",
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"@types/opentype.js": "^1.3.8",
|
||||
"@zerollup/ts-transform-paths": "^1.7.18",
|
||||
"cross-env": "^7.0.3",
|
||||
"cssnano": "^6.0.2",
|
||||
"dotenv": "^16.4.5",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-prettier": "^5.0.0",
|
||||
"lz-string": "^1.5.0",
|
||||
@@ -70,12 +75,7 @@
|
||||
"rollup-plugin-typescript2": "^0.34.1",
|
||||
"tslib": "^2.6.1",
|
||||
"ttypescript": "^1.5.15",
|
||||
"typescript": "^5.2.2",
|
||||
"@codemirror/commands": "^6.3.3",
|
||||
"@codemirror/language": "^6.10.0",
|
||||
"@codemirror/search": "^6.5.5",
|
||||
"@codemirror/state": "^6.4.0",
|
||||
"@codemirror/view": "^6.23.0"
|
||||
"typescript": "^5.2.2"
|
||||
},
|
||||
"resolutions": {
|
||||
"@typescript-eslint/typescript-estree": "5.3.0"
|
||||
|
||||
@@ -100,7 +100,13 @@ const BUILD_CONFIG = {
|
||||
plugins: getRollupPlugins(
|
||||
{tsconfig: isProd ? "tsconfig.json" : "tsconfig.dev.json"},
|
||||
...(isProd ? [
|
||||
terser({ toplevel: false, compress: { passes: 2 } }),
|
||||
terser({
|
||||
toplevel: false,
|
||||
compress: { passes: 2 },
|
||||
format: {
|
||||
comments: false, // Remove all comments
|
||||
},
|
||||
}),
|
||||
//!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
|
||||
|
||||
@@ -94,7 +94,10 @@ export const REGEX_TAGS = {
|
||||
export const REGEX_LINK = {
|
||||
//![[link|alias]] [alias](link){num}
|
||||
// 1 2 3 4 5 67 8 9
|
||||
EXPR: /(!)?(\[\[([^|\]]+)\|?([^\]]+)?]]|\[([^\]]*)]\(([^)]*)\))(\{(\d+)\})?/g, //https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/187
|
||||
//EXPR: /(!)?(\[\[([^|\]]+)\|?([^\]]+)?]]|\[([^\]]*)]\(([^)]*)\))(\{(\d+)\})?/g, //https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/187
|
||||
// 1 2 3 4 5 67 8 9
|
||||
EXPR: /(!)?(\[\[([^|\]]+)\|?([^\]]+)?]]|\[([^\]]*)]\(((?:[^\(\)]|\([^\(\)]*\))*)\))(\{(\d+)\})?/g, //https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/1963
|
||||
|
||||
getResList: (text: string): IteratorResult<RegExpMatchArray, any>[] => {
|
||||
const res = text.matchAll(REGEX_LINK.EXPR);
|
||||
let parts: IteratorResult<RegExpMatchArray, any>;
|
||||
|
||||
@@ -1534,8 +1534,16 @@ export default class ExcalidrawView extends TextFileView {
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseLeave = () => {
|
||||
if(!this.excalidrawAPI || !this.excalidrawData.loaded || !this.isDirty()) {
|
||||
return;
|
||||
}
|
||||
this.save();
|
||||
};
|
||||
|
||||
this.registerDomEvent(this.ownerWindow, "keydown", onKeyDown, false);
|
||||
this.registerDomEvent(this.ownerWindow, "keyup", onKeyUp, false);
|
||||
this.registerDomEvent(this.contentEl, "mouseleave", onMouseLeave, false);
|
||||
});
|
||||
|
||||
this.setupAutosaveTimer();
|
||||
@@ -3342,6 +3350,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
currentStrokeOptions: st.currentStrokeOptions,
|
||||
frameRendering: st.frameRendering,
|
||||
objectsSnapModeEnabled: st.objectsSnapModeEnabled,
|
||||
activeTool: st.activeTool,
|
||||
},
|
||||
prevTextMode: this.prevTextMode,
|
||||
files,
|
||||
@@ -5246,6 +5255,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
}
|
||||
|
||||
private renderWelcomeScreen () {
|
||||
if(!this.plugin.settings.showSplashscreen) return null;
|
||||
const React = this.packages.react;
|
||||
const {WelcomeScreen} = this.packages.excalidrawLib;
|
||||
const filecount = this.app.vault.getFiles().filter(f=>this.plugin.isExcalidrawFile(f)).length;
|
||||
|
||||
@@ -794,7 +794,9 @@ export const markdownPostProcessor = async (
|
||||
ctx: MarkdownPostProcessorContext,
|
||||
) => {
|
||||
const isPrinting = Boolean(document.body.querySelectorAll("body > .print").length>0);
|
||||
if(isPrinting && el.hasClass("mod-frontmatter")) {
|
||||
//firstElementChild: https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/1956
|
||||
const isFrontmatter = el.hasClass("mod-frontmatter") || el.firstElementChild?.hasClass("frontmatter");
|
||||
if(isPrinting && isFrontmatter) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -816,7 +818,7 @@ export const markdownPostProcessor = async (
|
||||
}
|
||||
|
||||
if (!isPreview && embeddedItems.length === 0) {
|
||||
if(el.hasClass("mod-frontmatter")) {
|
||||
if(isFrontmatter) {
|
||||
docIDs.add(ctx.docId);
|
||||
} else {
|
||||
if(docIDs.has(ctx.docId) && !el.hasChildNodes()) {
|
||||
|
||||
@@ -416,8 +416,14 @@ function RenderObsidianView(
|
||||
}
|
||||
} else if (leafRef.current?.node) {
|
||||
//Handle canvas node
|
||||
containerRef.current?.removeClasses(["is-editing", "is-focused"]);
|
||||
view.canvasNodeFactory.stopEditing(leafRef.current.node);
|
||||
if(view.plugin.settings.markdownNodeOneClickEditing && !containerRef.current?.hasClass("is-editing")) {
|
||||
const newTheme = getTheme(view, themeRef.current);
|
||||
containerRef.current?.addClasses(["is-editing", "is-focused"]);
|
||||
view.canvasNodeFactory.startEditing(leafRef.current.node, newTheme);
|
||||
} else {
|
||||
containerRef.current?.removeClasses(["is-editing", "is-focused"]);
|
||||
view.canvasNodeFactory.stopEditing(leafRef.current.node);
|
||||
}
|
||||
}
|
||||
}, [
|
||||
containerRef,
|
||||
@@ -428,7 +434,8 @@ function RenderObsidianView(
|
||||
element,
|
||||
view,
|
||||
isEditingRef,
|
||||
view.canvasNodeFactory
|
||||
view.canvasNodeFactory,
|
||||
themeRef.current
|
||||
]);
|
||||
|
||||
return null;
|
||||
|
||||
162
src/dialogs/HotkeyEditor.ts
Normal file
162
src/dialogs/HotkeyEditor.ts
Normal file
@@ -0,0 +1,162 @@
|
||||
import { BaseComponent, Setting, Modifier } from 'obsidian';
|
||||
import { DEVICE } from 'src/constants/constants';
|
||||
import { t } from 'src/lang/helpers';
|
||||
import { ExcalidrawSettings } from 'src/settings';
|
||||
import { modifierLabel } from 'src/utils/ModifierkeyHelper';
|
||||
import { fragWithHTML } from 'src/utils/Utils';
|
||||
|
||||
export class HotkeyEditor extends BaseComponent {
|
||||
private settings: ExcalidrawSettings;
|
||||
private containerEl: HTMLElement;
|
||||
private capturing: boolean = false;
|
||||
private activeModifiers: Modifier[] = [];
|
||||
public isDirty: boolean = false;
|
||||
private applySettingsUpdate: Function;
|
||||
|
||||
// Store bound event handlers
|
||||
private boundKeydownHandler: (event: KeyboardEvent) => void;
|
||||
private boundKeyupHandler: (event: KeyboardEvent) => void;
|
||||
|
||||
constructor(containerEl: HTMLElement, settings: ExcalidrawSettings, applySettingsUpdate: Function) {
|
||||
super();
|
||||
this.containerEl = containerEl.createDiv();
|
||||
this.settings = settings;
|
||||
this.applySettingsUpdate = applySettingsUpdate;
|
||||
|
||||
// Bind the event handlers once in the constructor
|
||||
this.boundKeydownHandler = this.onKeydown.bind(this);
|
||||
this.boundKeyupHandler = this.onKeyup.bind(this);
|
||||
}
|
||||
|
||||
onload(): void {
|
||||
this.render();
|
||||
}
|
||||
|
||||
private render(): void {
|
||||
// Clear previous content
|
||||
this.containerEl.empty();
|
||||
|
||||
// Render current overrides
|
||||
this.settings.modifierKeyOverrides.forEach((override, index) => {
|
||||
const key = override.key.toUpperCase();
|
||||
new Setting(this.containerEl)
|
||||
.setDesc(fragWithHTML(`<b>Code:</b> <kbd>${override.modifiers.join("+")} + ${key}</kbd> | ` +
|
||||
`<b>Apple:</b> <kbd>${modifierLabel(override.modifiers, "Mac")} + ${key}</kbd> | ` +
|
||||
`<b>Windows:</b> <kbd>${modifierLabel(override.modifiers, "Other")} + ${key}</kbd>`))
|
||||
.addButton((button) =>
|
||||
button
|
||||
.setButtonText(t("HOTKEY_BUTTON_REMOVE"))
|
||||
.setCta()
|
||||
.onClick(() => {
|
||||
this.settings.modifierKeyOverrides.splice(index, 1);
|
||||
this.isDirty = true;
|
||||
this.applySettingsUpdate();
|
||||
this.render();
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
// Render Add New Override or Capture Instruction
|
||||
if (this.capturing) {
|
||||
new Setting(this.containerEl)
|
||||
.setName(t("HOTKEY_PRESS_COMBO_NANE"))
|
||||
.setDesc(t("HOTKEY_PRESS_COMBO_DESC"))
|
||||
.controlEl.style.cursor = 'pointer';
|
||||
} else {
|
||||
new Setting(this.containerEl)
|
||||
.addButton((button) =>
|
||||
button
|
||||
.setButtonText(t("HOTKEY_BUTTON_ADD_OVERRIDE"))
|
||||
.setCta()
|
||||
.onClick(() => this.startCapture())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private startCapture(): void {
|
||||
this.capturing = true;
|
||||
this.activeModifiers = [];
|
||||
this.render();
|
||||
// Use the pre-bound handlers
|
||||
window.addEventListener('keydown', this.boundKeydownHandler);
|
||||
window.addEventListener('keyup', this.boundKeyupHandler);
|
||||
}
|
||||
|
||||
private onKeydown(event: KeyboardEvent): void {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
const modifiers = this.getModifiersFromEvent(event);
|
||||
|
||||
// If only modifiers are pressed, update activeModifiers and continue listening
|
||||
if (['Control', 'Shift', 'Alt', 'Meta'].includes(event.key)) {
|
||||
this.activeModifiers = modifiers;
|
||||
return;
|
||||
}
|
||||
|
||||
const key = event.key.length === 1 ? event.key.toLowerCase() : event.key;
|
||||
|
||||
// Check for duplicate overrides
|
||||
const exists = this.settings.modifierKeyOverrides.some(
|
||||
(override) =>
|
||||
override.key === key &&
|
||||
override.modifiers.length === modifiers.length &&
|
||||
override.modifiers.every((mod) => modifiers.includes(mod))
|
||||
);
|
||||
|
||||
if (!exists) {
|
||||
this.settings.modifierKeyOverrides.push({ modifiers, key });
|
||||
this.isDirty = true;
|
||||
this.applySettingsUpdate();
|
||||
}
|
||||
|
||||
this.stopCapture();
|
||||
}
|
||||
|
||||
private onKeyup(event: KeyboardEvent): void {
|
||||
// If all modifier keys are released, stop capturing
|
||||
if (!event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey) {
|
||||
this.stopCapture();
|
||||
}
|
||||
}
|
||||
|
||||
private stopCapture(): void {
|
||||
this.capturing = false;
|
||||
// Use the pre-bound handlers for removal
|
||||
window.removeEventListener('keydown', this.boundKeydownHandler);
|
||||
window.removeEventListener('keyup', this.boundKeyupHandler);
|
||||
this.render();
|
||||
}
|
||||
|
||||
public unload(): void {
|
||||
// Ensure listeners are removed when the component is unloaded
|
||||
this.stopCapture();
|
||||
}
|
||||
|
||||
private getModifiersFromEvent(event: KeyboardEvent): Modifier[] {
|
||||
const modifiers: Modifier[] = [];
|
||||
|
||||
if (DEVICE.isMacOS && event.metaKey) {
|
||||
modifiers.push('Mod');
|
||||
} else if (!DEVICE.isMacOS && event.ctrlKey) {
|
||||
modifiers.push('Mod');
|
||||
}
|
||||
|
||||
if (DEVICE.isMacOS && event.ctrlKey) {
|
||||
modifiers.push('Ctrl');
|
||||
}
|
||||
|
||||
if (!DEVICE.isMacOS && event.metaKey) {
|
||||
modifiers.push('Meta');
|
||||
}
|
||||
|
||||
if (event.shiftKey) {
|
||||
modifiers.push('Shift');
|
||||
}
|
||||
if (event.altKey) {
|
||||
modifiers.push('Alt');
|
||||
}
|
||||
|
||||
return modifiers;
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,7 @@ export default {
|
||||
TRANSCLUDE: "Embed a drawing",
|
||||
TRANSCLUDE_MOST_RECENT: "Embed the most recently edited drawing",
|
||||
TOGGLE_LEFTHANDED_MODE: "Toggle left-handed mode",
|
||||
TOGGLE_SPLASHSCREEN: "Show splash screen in new drawings",
|
||||
FLIP_IMAGE: "Open the back-of-the-note of the selected excalidraw image",
|
||||
NEW_IN_NEW_PANE: "Create new drawing - IN AN ADJACENT WINDOW",
|
||||
NEW_IN_NEW_TAB: "Create new drawing - IN A NEW TAB",
|
||||
@@ -352,6 +353,10 @@ FILENAME_HEAD: "Filename",
|
||||
"<li>When <b>disabled</b> the PDF will show the markdown side of the document.</li></ul>" +
|
||||
"See the other related setting for <a href='#"+TAG_MDREADINGMODE+"'>Markdown Reading Mode</a> under 'Appearnace and Behavior' further above.<br>" +
|
||||
"⚠️ Note, you must close the active excalidraw/markdown file and reopen for this change to take effect. ⚠️",
|
||||
HOTKEY_OVERRIDE_HEAD: "Hotkey overrides",
|
||||
HOTKEY_OVERRIDE_DESC: `Some of the Excalidraw hotkeys such as <code>${labelCTRL()}+Enter</code> to edit text or <code>${labelCTRL()}+K</code> to create an element link ` +
|
||||
"conflict with Obsidian hotkey settings. The hotkey combinations you add below will override Obsidian's hotkey settings while useing Excalidraw, thus " +
|
||||
`you can add <code>${labelCTRL()}+G</code> if you want to default to Group Object in Excalidraw instead of opening Graph View.`,
|
||||
THEME_HEAD: "Theme and styling",
|
||||
ZOOM_HEAD: "Zoom",
|
||||
DEFAULT_PINCHZOOM_NAME: "Allow pinch zoom in pen mode",
|
||||
@@ -477,7 +482,11 @@ FILENAME_HEAD: "Filename",
|
||||
EMBED_TOEXCALIDRAW_DESC: "In the Embed Files section of Excalidraw Settings, you can configure how various files are embedded into Excalidraw. This includes options for embedding interactive markdown files, PDFs, and markdown files as images.",
|
||||
MD_HEAD: "Embed markdown into Excalidraw as image",
|
||||
MD_EMBED_CUSTOMDATA_HEAD_NAME: "Interactive Markdown Files",
|
||||
MD_EMBED_CUSTOMDATA_HEAD_DESC: `These settings will only effect future embeds. Current embeds remain unchanged. The theme setting of embedded frames is under the "Excalidraw appearance and behavior" section.`,
|
||||
MD_EMBED_CUSTOMDATA_HEAD_DESC: `The below settings will only effect future embeds. Current embeds remain unchanged. The theme setting of embedded frames is under the "Excalidraw appearance and behavior" section.`,
|
||||
MD_EMBED_SINGLECLICK_EDIT_NAME: "Single click to edit embedded markdown",
|
||||
MD_EMBED_SINGLECLICK_EDIT_DESC:
|
||||
"Single click on an embedded markdown file to edit it. " +
|
||||
"When turned off, the markdown file will first open in preview mode, then switch to edit mode when you click on it again.",
|
||||
MD_TRANSCLUDE_WIDTH_NAME: "Default width of a transcluded markdown document",
|
||||
MD_TRANSCLUDE_WIDTH_DESC:
|
||||
"The width of the markdown page. This affects the word wrapping when transcluding longer paragraphs, and the width of " +
|
||||
@@ -735,6 +744,12 @@ FILENAME_HEAD: "Filename",
|
||||
"the developer of Taskbone (as you can imagine, there is no such thing as 'free', providing this awesome OCR service costs some money to the developer of Taskbone), you can " +
|
||||
"purchase a paid API key from <a href='https://www.taskbone.com/' target='_blank'>taskbone.com</a>. In case you have purchased a key, simply overwrite this auto generated free-tier API-key with your paid key.",
|
||||
|
||||
//HotkeyEditor
|
||||
HOTKEY_PRESS_COMBO_NANE: "Press your hotkey combination",
|
||||
HOTKEY_PRESS_COMBO_DESC: "Please press the desired key combination",
|
||||
HOTKEY_BUTTON_ADD_OVERRIDE: "Add New Override",
|
||||
HOTKEY_BUTTON_REMOVE: "Remove",
|
||||
|
||||
//openDrawings.ts
|
||||
SELECT_FILE: "Select a file then press enter.",
|
||||
SELECT_COMMAND: "Select a command then press enter.",
|
||||
|
||||
@@ -477,7 +477,11 @@ FILENAME_HEAD: "文件名",
|
||||
EMBED_TOEXCALIDRAW_DESC: "包括:以图像形式嵌入到绘图中的 PDF 文档、以交互形式嵌入到绘图中的 Markdown 文档(MD-Embeddable)、以图像形式嵌入的 Markdown 文档(MD-Embed)等。",
|
||||
MD_HEAD: "以图像形式嵌入到绘图中的 Markdown 文档(MD-Embed)",
|
||||
MD_EMBED_CUSTOMDATA_HEAD_NAME: "以交互形式嵌入到绘图中的 Markdown 文档(MD-Embeddable)",
|
||||
MD_EMBED_CUSTOMDATA_HEAD_DESC: `这些选项不会影响到已存在的 MD-Embeddable。MD-Embeddable 的主题风格在“显示 & 行为”小节设置。`,
|
||||
MD_EMBED_CUSTOMDATA_HEAD_DESC: `以下设置只会影响以后的嵌入。已存在的嵌入保持不变。嵌入框的主题设置位于 “Excalidraw 外观和行为” 部分。`,
|
||||
MD_EMBED_SINGLECLICK_EDIT_NAME: "单击以编辑嵌入的 markdown。",
|
||||
MD_EMBED_SINGLECLICK_EDIT_DESC:
|
||||
"单击嵌入的 markdown 文件以进行编辑。 " +
|
||||
"当此功能关闭时,markdown 文件将首先以预览模式打开,然后在您再次单击时切换到编辑模式。",
|
||||
MD_TRANSCLUDE_WIDTH_NAME: "MD-Embed 的默认宽度",
|
||||
MD_TRANSCLUDE_WIDTH_DESC:
|
||||
"MD-Embed 的宽度。该选项会影响到折行,以及图像元素的宽度。<br>" +
|
||||
|
||||
76
src/main.ts
76
src/main.ts
@@ -2826,37 +2826,53 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
this.popScope = null;
|
||||
}
|
||||
if (newActiveviewEV) {
|
||||
const scope = this.app.keymap.getRootScope();
|
||||
const handler_ctrlEnter = scope.register(["Mod"], "Enter", () => true);
|
||||
scope.keys.unshift(scope.keys.pop()); // Force our handler to the front of the list
|
||||
const handler_ctrlK = scope.register(["Mod"], "k", () => true);
|
||||
scope.keys.unshift(scope.keys.pop()); // Force our handler to the front of the list
|
||||
const handler_ctrlF = scope.register(["Mod"], "f", () => {
|
||||
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
||||
if (view) {
|
||||
search(view);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
scope.keys.unshift(scope.keys.pop()); // Force our handler to the front of the list
|
||||
const overridSaveShortcut = (
|
||||
this.forceSaveCommand &&
|
||||
this.forceSaveCommand.hotkeys[0].key === "s" &&
|
||||
this.forceSaveCommand.hotkeys[0].modifiers.includes("Ctrl")
|
||||
)
|
||||
const saveHandler = overridSaveShortcut
|
||||
? scope.register(["Ctrl"], "s", () => this.forceSaveActiveView(false))
|
||||
: undefined;
|
||||
if(saveHandler) {
|
||||
scope.keys.unshift(scope.keys.pop()); // Force our handler to the front of the list
|
||||
}
|
||||
this.popScope = () => {
|
||||
scope.unregister(handler_ctrlEnter);
|
||||
scope.unregister(handler_ctrlK);
|
||||
scope.unregister(handler_ctrlF);
|
||||
Boolean(saveHandler) && scope.unregister(saveHandler);
|
||||
this.registerHotkeyOverrides();
|
||||
}
|
||||
}
|
||||
|
||||
public registerHotkeyOverrides() {
|
||||
//this is repeated here because the same function is called when settings is closed after hotkeys have changed
|
||||
if (this.popScope) {
|
||||
this.popScope();
|
||||
this.popScope = null;
|
||||
}
|
||||
|
||||
if(!this.activeExcalidrawView) {
|
||||
return;
|
||||
}
|
||||
|
||||
const scope = this.app.keymap.getRootScope();
|
||||
// Register overrides from settings
|
||||
const overrideHandlers = this.settings.modifierKeyOverrides.map(override => {
|
||||
return scope.register(override.modifiers, override.key, () => true);
|
||||
});
|
||||
// Force handlers to the front of the list
|
||||
overrideHandlers.forEach(() => scope.keys.unshift(scope.keys.pop()));
|
||||
|
||||
const handler_ctrlF = scope.register(["Mod"], "f", () => {
|
||||
const view = this.app.workspace.getActiveViewOfType(ExcalidrawView);
|
||||
if (view) {
|
||||
search(view);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
scope.keys.unshift(scope.keys.pop()); // Force our handler to the front of the list
|
||||
const overridSaveShortcut = (
|
||||
this.forceSaveCommand &&
|
||||
this.forceSaveCommand.hotkeys[0].key === "s" &&
|
||||
this.forceSaveCommand.hotkeys[0].modifiers.includes("Ctrl")
|
||||
)
|
||||
const saveHandler = overridSaveShortcut
|
||||
? scope.register(["Ctrl"], "s", () => this.forceSaveActiveView(false))
|
||||
: undefined;
|
||||
if(saveHandler) {
|
||||
scope.keys.unshift(scope.keys.pop()); // Force our handler to the front of the list
|
||||
}
|
||||
this.popScope = () => {
|
||||
overrideHandlers.forEach(handler => scope.unregister(handler));
|
||||
scope.unregister(handler_ctrlF);
|
||||
Boolean(saveHandler) && scope.unregister(saveHandler);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
ButtonComponent,
|
||||
DropdownComponent,
|
||||
getIcon,
|
||||
Modifier,
|
||||
normalizePath,
|
||||
PluginSettingTab,
|
||||
Setting,
|
||||
@@ -39,6 +40,7 @@ import { EDITOR_FADEOUT } from "./CodeMirrorExtension/EditorHandler";
|
||||
import { setDebugging } from "./utils/DebugHelper";
|
||||
import { Rank } from "./menu/ActionIcons";
|
||||
import { TAG_AUTOEXPORT, TAG_MDREADINGMODE, TAG_PDFEXPORT } from "src/constants/constSettingsTags";
|
||||
import { HotkeyEditor } from "./dialogs/HotkeyEditor";
|
||||
|
||||
export interface ExcalidrawSettings {
|
||||
folder: string;
|
||||
@@ -183,6 +185,7 @@ export interface ExcalidrawSettings {
|
||||
COLOR: string,
|
||||
};
|
||||
embeddableMarkdownDefaults: EmbeddableMDCustomProps;
|
||||
markdownNodeOneClickEditing: boolean;
|
||||
canvasImmersiveEmbed: boolean,
|
||||
startupScriptPath: string,
|
||||
openAIAPIToken: string,
|
||||
@@ -203,6 +206,8 @@ export interface ExcalidrawSettings {
|
||||
longPressMobile: number;
|
||||
isDebugMode: boolean;
|
||||
rank: Rank;
|
||||
modifierKeyOverrides: {modifiers: Modifier[], key: string}[];
|
||||
showSplashscreen: boolean;
|
||||
}
|
||||
|
||||
declare const PLUGIN_VERSION:string;
|
||||
@@ -366,6 +371,7 @@ export const DEFAULT_SETTINGS: ExcalidrawSettings = {
|
||||
borderOpacity: 0,
|
||||
filenameVisible: false,
|
||||
},
|
||||
markdownNodeOneClickEditing: false,
|
||||
canvasImmersiveEmbed: true,
|
||||
startupScriptPath: "",
|
||||
openAIAPIToken: "",
|
||||
@@ -462,6 +468,11 @@ export const DEFAULT_SETTINGS: ExcalidrawSettings = {
|
||||
longPressMobile: 500,
|
||||
isDebugMode: false,
|
||||
rank: "Bronze",
|
||||
modifierKeyOverrides: [
|
||||
{modifiers: ["Mod"], key:"Enter"},
|
||||
{modifiers: ["Mod"], key:"k"},
|
||||
],
|
||||
showSplashscreen: true,
|
||||
};
|
||||
|
||||
export class ExcalidrawSettingTab extends PluginSettingTab {
|
||||
@@ -470,6 +481,7 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
|
||||
private requestReloadDrawings: boolean = false;
|
||||
private requestUpdatePinnedPens: boolean = false;
|
||||
private requestUpdateDynamicStyling: boolean = false;
|
||||
private hotkeyEditor: HotkeyEditor;
|
||||
//private reloadMathJax: boolean = false;
|
||||
//private applyDebounceTimer: number = 0;
|
||||
|
||||
@@ -496,21 +508,25 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
|
||||
}
|
||||
this.plugin.saveSettings();
|
||||
if (this.requestUpdatePinnedPens) {
|
||||
app.workspace.getLeavesOfType(VIEW_TYPE_EXCALIDRAW).forEach(v=> {
|
||||
this.app.workspace.getLeavesOfType(VIEW_TYPE_EXCALIDRAW).forEach(v=> {
|
||||
if (v.view instanceof ExcalidrawView) v.view.updatePinnedCustomPens()
|
||||
})
|
||||
}
|
||||
if (this.requestUpdateDynamicStyling) {
|
||||
app.workspace.getLeavesOfType(VIEW_TYPE_EXCALIDRAW).forEach(v=> {
|
||||
this.app.workspace.getLeavesOfType(VIEW_TYPE_EXCALIDRAW).forEach(v=> {
|
||||
if (v.view instanceof ExcalidrawView) {
|
||||
setDynamicStyle(this.plugin.ea,v.view,v.view.previousBackgroundColor,this.plugin.settings.dynamicStyling);
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
this.hotkeyEditor.unload();
|
||||
if (this.hotkeyEditor.isDirty) {
|
||||
this.plugin.registerHotkeyOverrides();
|
||||
}
|
||||
if (this.requestReloadDrawings) {
|
||||
const exs =
|
||||
app.workspace.getLeavesOfType(VIEW_TYPE_EXCALIDRAW);
|
||||
this.app.workspace.getLeavesOfType(VIEW_TYPE_EXCALIDRAW);
|
||||
for (const v of exs) {
|
||||
if (v.view instanceof ExcalidrawView) {
|
||||
await v.view.save(false);
|
||||
@@ -1093,6 +1109,29 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
|
||||
);
|
||||
addIframe(detailsEl, "H8Njp7ZXYag",999);
|
||||
|
||||
new Setting(detailsEl)
|
||||
.setName(t("TOGGLE_SPLASHSCREEN"))
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.showSplashscreen)
|
||||
.onChange((value)=> {
|
||||
this.plugin.settings.showSplashscreen = value;
|
||||
this.applySettingsUpdate();
|
||||
})
|
||||
)
|
||||
|
||||
detailsEl = displayDetailsEl.createEl("details");
|
||||
detailsEl.createEl("summary", {
|
||||
text: t("HOTKEY_OVERRIDE_HEAD"),
|
||||
cls: "excalidraw-setting-h3",
|
||||
});
|
||||
detailsEl.createEl("span", {}, (el) => {
|
||||
el.innerHTML = t("HOTKEY_OVERRIDE_DESC");
|
||||
});
|
||||
|
||||
this.hotkeyEditor = new HotkeyEditor(detailsEl, this.plugin.settings, this.applySettingsUpdate);
|
||||
this.hotkeyEditor.onload();
|
||||
|
||||
detailsEl = displayDetailsEl.createEl("details");
|
||||
detailsEl.createEl("summary", {
|
||||
text: t("THEME_HEAD"),
|
||||
@@ -2125,7 +2164,26 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
|
||||
text: t("MD_EMBED_CUSTOMDATA_HEAD_NAME"),
|
||||
cls: "excalidraw-setting-h3",
|
||||
});
|
||||
detailsEl.createEl("span", {text: t("MD_EMBED_CUSTOMDATA_HEAD_DESC")});
|
||||
|
||||
new Setting(detailsEl)
|
||||
.setName(t("MD_EMBED_SINGLECLICK_EDIT_NAME"))
|
||||
.setDesc(fragWithHTML(t("MD_EMBED_SINGLECLICK_EDIT_DESC")))
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.markdownNodeOneClickEditing)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.markdownNodeOneClickEditing = value;
|
||||
this.applySettingsUpdate();
|
||||
})
|
||||
);
|
||||
|
||||
detailsEl.createEl("hr", { cls: "excalidraw-setting-hr" });
|
||||
detailsEl.createEl("span", {}, (el) => {
|
||||
el.innerHTML = t("MD_EMBED_CUSTOMDATA_HEAD_DESC");
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
new EmbeddalbeMDFileCustomDataSettingsComponent(
|
||||
detailsEl,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Modifier } from "obsidian";
|
||||
import { DEVICE } from "src/constants/constants";
|
||||
import { ExcalidrawSettings } from "src/settings";
|
||||
export type ModifierKeys = {shiftKey:boolean, ctrlKey: boolean, metaKey: boolean, altKey: boolean};
|
||||
@@ -177,4 +178,26 @@ export const emulateKeysForLinkClick = (action: PaneTarget): ModifierKeys => {
|
||||
|
||||
export const anyModifierKeysPressed = (e: ModifierKeys): boolean => {
|
||||
return e.shiftKey || e.ctrlKey || e.metaKey || e.altKey;
|
||||
}
|
||||
|
||||
export function modifierLabel(modifiers: Modifier[], platform?: "Mac" | "Other"): string {
|
||||
const isMacPlatform = platform === "Mac" ||
|
||||
(platform === undefined && (DEVICE.isIOS || DEVICE.isMacOS));
|
||||
|
||||
return modifiers.map(modifier => {
|
||||
switch (modifier) {
|
||||
case "Mod":
|
||||
return isMacPlatform ? "CMD" : "CTRL";
|
||||
case "Ctrl":
|
||||
return "CTRL";
|
||||
case "Meta":
|
||||
return isMacPlatform ? "CMD" : "WIN";
|
||||
case "Shift":
|
||||
return "SHIFT";
|
||||
case "Alt":
|
||||
return isMacPlatform ? "OPTION" : "ALT";
|
||||
default:
|
||||
return modifier;
|
||||
}
|
||||
}).join("+");
|
||||
}
|
||||
@@ -625,4 +625,8 @@ textarea.excalidraw-wysiwyg, .excalidraw input {
|
||||
.excalidraw-rank svg {
|
||||
height: 8rem;
|
||||
width: 8rem;
|
||||
}
|
||||
|
||||
.excalidraw .color-picker-content input[type="color"] {
|
||||
filter: var(--theme-filter);
|
||||
}
|
||||
Reference in New Issue
Block a user