mirror of
https://github.com/zsviczian/obsidian-excalidraw-plugin.git
synced 2025-08-06 05:46:28 +00:00
2.0.5
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 949 KiB After Width: | Height: | Size: 409 KiB |
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "obsidian-excalidraw-plugin",
|
||||
"name": "Excalidraw",
|
||||
"version": "2.0.4",
|
||||
"version": "2.0.5",
|
||||
"minAppVersion": "1.1.6",
|
||||
"description": "An Obsidian plugin to edit and view Excalidraw drawings",
|
||||
"author": "Zsolt Viczian",
|
||||
|
||||
@@ -396,6 +396,15 @@ export class EmbeddedFilesLoader {
|
||||
return {dataURL: dURL as DataURL, hasSVGwithBitmap};
|
||||
};
|
||||
|
||||
//this is a fix for backward compatibility - I messed up with generating the local link
|
||||
private getLocalPath(path: string) {
|
||||
const localPath = path.split("file://")[1]
|
||||
if(localPath.startsWith("/")) {
|
||||
return localPath.substring(1);
|
||||
}
|
||||
return localPath;
|
||||
}
|
||||
|
||||
private async _getObsidianImage(inFile: TFile | EmbeddedFile, depth: number): Promise<ImgData> {
|
||||
if (!this.plugin || !inFile) {
|
||||
return null;
|
||||
@@ -442,7 +451,7 @@ export class EmbeddedFilesLoader {
|
||||
const ab = isHyperLink || isPDF
|
||||
? null
|
||||
: isLocalLink
|
||||
? await readLocalFileBinary((inFile as EmbeddedFile).hyperlink.split("file://")[1])
|
||||
? await readLocalFileBinary(this.getLocalPath((inFile as EmbeddedFile).hyperlink))
|
||||
: await app.vault.readBinary(file);
|
||||
|
||||
let dURL: DataURL = null;
|
||||
@@ -535,7 +544,7 @@ export class EmbeddedFilesLoader {
|
||||
//debug({where:"EmbeddedFileLoader.loadSceneFiles",uid:this.uid,status:"embedded Files are not loaded"});
|
||||
const data = await this._getObsidianImage(embeddedFile, depth);
|
||||
if (data) {
|
||||
const fileData = {
|
||||
const fileData: FileData = {
|
||||
mimeType: data.mimeType,
|
||||
id: entry.value[0],
|
||||
dataURL: data.dataURL,
|
||||
|
||||
@@ -73,6 +73,7 @@ import {
|
||||
download,
|
||||
getDataURLFromURL,
|
||||
getIMGFilename,
|
||||
getInternalLinkOrFileURLLink,
|
||||
getMimeType,
|
||||
getNewUniqueFilepath,
|
||||
getURLImageExtension,
|
||||
@@ -119,7 +120,7 @@ import { getTextElementAtPointer, getImageElementAtPointer, getElementWithLinkAt
|
||||
import { ICONS, LogoWrapper, saveIcon } from "./menu/ActionIcons";
|
||||
import { ExportDialog } from "./dialogs/ExportDialog";
|
||||
import { getEA } from "src"
|
||||
import { anyModifierKeysPressed, emulateKeysForLinkClick, externalDragModifierType, internalDragModifierType, isALT, isCTRL, isMETA, isSHIFT, linkClickModifierType, localFileDragModifierType, ModifierKeys } from "./utils/ModifierkeyHelper";
|
||||
import { anyModifierKeysPressed, emulateKeysForLinkClick, webbrowserDragModifierType, internalDragModifierType, isWinALTorMacOPT, isWinCTRLorMacCMD, isWinMETAorMacCTRL, isSHIFT, linkClickModifierType, localFileDragModifierType, ModifierKeys, modifierKeyTooltipMessages } from "./utils/ModifierkeyHelper";
|
||||
import { setDynamicStyle } from "./utils/DynamicStyling";
|
||||
import { InsertPDFModal } from "./dialogs/InsertPDFModal";
|
||||
import { CustomEmbeddable, renderWebView } from "./customEmbeddable";
|
||||
@@ -3041,16 +3042,16 @@ export default class ExcalidrawView extends TextFileView {
|
||||
if (this.isFullscreen() && event.keyCode === KEYCODE.ESC) {
|
||||
this.exitFullscreen();
|
||||
}
|
||||
if (isCTRL(event) && !isSHIFT(event) && !isALT(event)) {
|
||||
if (isWinCTRLorMacCMD(event) && !isSHIFT(event) && !isWinALTorMacOPT(event)) {
|
||||
this.showHoverPreview();
|
||||
}
|
||||
};
|
||||
|
||||
private onPointerDown(e: PointerEvent) {
|
||||
if (!(isCTRL(e)||isMETA(e))) {
|
||||
if (!(isWinCTRLorMacCMD(e)||isWinMETAorMacCTRL(e))) {
|
||||
return;
|
||||
}
|
||||
if (!this.plugin.settings.allowCtrlClick && !!isMETA(e)) {
|
||||
if (!this.plugin.settings.allowCtrlClick && !!isWinMETAorMacCTRL(e)) {
|
||||
return;
|
||||
}
|
||||
//added setTimeout when I changed onClick(e: MouseEvent) to onPointerDown() in 1.7.9.
|
||||
@@ -3081,31 +3082,18 @@ export default class ExcalidrawView extends TextFileView {
|
||||
let msg: string = "";
|
||||
if((this.app as any).dragManager.draggable) {
|
||||
//drag from Obsidian file manager
|
||||
switch (internalDragModifierType(e)) {
|
||||
case "image": msg = "Embed image";break;
|
||||
case "image-fullsize": msg = "Embed image @100%"; break;
|
||||
case "link": msg = `Insert link\n${DEVICE.isMacOS || DEVICE.isIOS
|
||||
? "try SHIFT and CTRL combinations for other drop actions"
|
||||
: "try SHIFT, CTRL, ALT combinations for other drop actions"}`; break;
|
||||
case "embeddable": msg = "Insert in interactive frame"; break;
|
||||
}
|
||||
msg = modifierKeyTooltipMessages().InternalDragAction[internalDragModifierType(e)];
|
||||
} else if(e.dataTransfer.types.length === 1 && e.dataTransfer.types.includes("Files")) {
|
||||
//drag from OS file manager
|
||||
switch (localFileDragModifierType(e)) {
|
||||
case "image-import": msg = "Import image to Vault"; break;
|
||||
case "image-uri": msg = `Insert image with local URI`; break;
|
||||
case "insert-link": msg = "Insert link"; break;
|
||||
}
|
||||
msg = modifierKeyTooltipMessages().LocalFileDragAction[localFileDragModifierType(e)];
|
||||
} else {
|
||||
//drag from Internet
|
||||
switch (externalDragModifierType(e)) {
|
||||
case "image-import": msg = "Import image to Vault"; break;
|
||||
case "image-url": msg = `Insert image/thumbnail with URL\n${DEVICE.isMacOS || DEVICE.isIOS
|
||||
? "try SHIFT, OPT, CTRL combinations for other drop actions"
|
||||
: "try SHIFT, CTRL, ALT combinations for other drop actions"}`; break;
|
||||
case "insert-link": msg = "Insert link"; break;
|
||||
case "embeddable": msg = "Insert in interactive frame"; break;
|
||||
}
|
||||
msg = modifierKeyTooltipMessages().WebBrowserDragAction[webbrowserDragModifierType(e)];
|
||||
}
|
||||
if(!e.shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey) {
|
||||
msg += DEVICE.isMacOS || DEVICE.isIOS
|
||||
? "\nTry SHIFT, OPT, CTRL combinations for other drop actions"
|
||||
: "\nTry SHIFT, CTRL, ALT combinations for other drop actions";
|
||||
}
|
||||
if(this.draginfoDiv.innerText !== msg) this.draginfoDiv.innerText = msg;
|
||||
const top = `${e.clientY-parseFloat(getComputedStyle(this.draginfoDiv).fontSize)*8}px`;
|
||||
@@ -3147,7 +3135,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
this.blockOnMouseButtonDown = true;
|
||||
|
||||
//ctrl click
|
||||
if (isCTRL(this.modifierKeyDown) || isMETA(this.modifierKeyDown)) {
|
||||
if (isWinCTRLorMacCMD(this.modifierKeyDown) || isWinMETAorMacCTRL(this.modifierKeyDown)) {
|
||||
this.identifyElementClicked();
|
||||
return;
|
||||
}
|
||||
@@ -3163,7 +3151,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
if (p.button === "up") {
|
||||
this.blockOnMouseButtonDown = false;
|
||||
}
|
||||
if (isCTRL(this.modifierKeyDown) ||
|
||||
if (isWinCTRLorMacCMD(this.modifierKeyDown) ||
|
||||
(this.excalidrawAPI.getAppState().isViewModeEnabled &&
|
||||
this.plugin.settings.hoverPreviewWithoutCTRL)) {
|
||||
|
||||
@@ -3349,7 +3337,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
);
|
||||
const draggable = (app as any).dragManager.draggable;
|
||||
const internalDragAction = internalDragModifierType(event);
|
||||
const externalDragAction = externalDragModifierType(event);
|
||||
const externalDragAction = webbrowserDragModifierType(event);
|
||||
const localFileDragAction = localFileDragModifierType(event);
|
||||
|
||||
//Call Excalidraw Automate onDropHook
|
||||
@@ -3525,7 +3513,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
this.addImageWithURL(text);
|
||||
return false;
|
||||
}
|
||||
if(text && (externalDragAction === "insert-link")) {
|
||||
if(text && (externalDragAction === "link")) {
|
||||
if (
|
||||
this.plugin.settings.iframelyAllowed &&
|
||||
text.match(/^https?:\/\/\S*$/)
|
||||
@@ -3555,7 +3543,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
this.addImageWithURL(src[1]);
|
||||
return false;
|
||||
}
|
||||
if(src && (externalDragAction === "insert-link")) {
|
||||
if(src && (externalDragAction === "link")) {
|
||||
if (
|
||||
this.plugin.settings.iframelyAllowed &&
|
||||
src[1].match(/^https?:\/\/\S*$/)
|
||||
@@ -3577,30 +3565,57 @@ export default class ExcalidrawView extends TextFileView {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(event.dataTransfer.types.length >= 1 && localFileDragAction === "image-uri") {
|
||||
(async () => {
|
||||
for(let i=0;i<event.dataTransfer.files.length;i++) {
|
||||
//@ts-ignore
|
||||
const path = encodeURI(event.dataTransfer.files[i].path);
|
||||
const {x,y} = this.currentPosition;
|
||||
await insertImageToView(getEA(this), {x:x+i*300, y:y+i*300}, `file://${path}`);
|
||||
|
||||
if (event.dataTransfer.types.length >= 1 && ["image-url","image-import","embeddable"].contains(localFileDragAction)) {
|
||||
for(let i=0;i<event.dataTransfer.files.length;i++) {
|
||||
//@ts-ignore
|
||||
const path = event.dataTransfer.files[i].path;
|
||||
if(!path) return true; //excalidarw to continue processing
|
||||
const link = getInternalLinkOrFileURLLink(path, this.plugin, event.dataTransfer.files[i].name, this.file);
|
||||
const {x,y} = this.currentPosition;
|
||||
const pos = {x:x+i*300, y:y+i*300};
|
||||
if(link.isInternal) {
|
||||
if(localFileDragAction === "embeddable") {
|
||||
insertEmbeddableToView(getEA(this), pos, link.file);
|
||||
} else {
|
||||
insertImageToView(getEA(this), pos, link.file);
|
||||
}
|
||||
} else {
|
||||
const extension = getURLImageExtension(link.url);
|
||||
if(
|
||||
localFileDragAction === "image-import" &&
|
||||
(IMAGE_TYPES.contains(extension) || extension === "excalidraw")
|
||||
) {
|
||||
return true; //excalidarw to continue processing
|
||||
}
|
||||
if(localFileDragAction === "embeddable" || !IMAGE_TYPES.contains(extension)) {
|
||||
insertEmbeddableToView(getEA(this), pos, null, link.url);
|
||||
if(localFileDragAction !== "embeddable") {
|
||||
new Notice("Not imported to Vault. Embedded with local URI");
|
||||
}
|
||||
} else {
|
||||
insertImageToView(getEA(this), pos, link.url);
|
||||
}
|
||||
}
|
||||
})();
|
||||
};
|
||||
return false;
|
||||
}
|
||||
|
||||
if(event.dataTransfer.types.length >= 1 && localFileDragAction === "insert-link") {
|
||||
if(event.dataTransfer.types.length >= 1 && localFileDragAction === "link") {
|
||||
const ea = getEA(this) as ExcalidrawAutomate;
|
||||
for(let i=0;i<event.dataTransfer.files.length;i++) {
|
||||
//@ts-ignore
|
||||
const path = event.dataTransfer.files[i].path;
|
||||
const name = event.dataTransfer.files[i].name;
|
||||
if(!path || !name) return true; //excalidarw to continue processing
|
||||
const link = getInternalLinkOrFileURLLink(path, this.plugin, name, this.file);
|
||||
const id = ea.addText(
|
||||
this.currentPosition.x+i*40,
|
||||
this.currentPosition.y+i*20,
|
||||
`📂 ${name}`);
|
||||
ea.getElement(id).link = `[${name}](file://${path})`;
|
||||
link.isInternal ? link.link :`📂 ${name}`);
|
||||
if(!link.isInternal) {
|
||||
ea.getElement(id).link = link.link;
|
||||
}
|
||||
}
|
||||
ea.addElementsToView();
|
||||
return false;
|
||||
@@ -3898,7 +3913,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
|
||||
let event = e?.detail?.nativeEvent;
|
||||
if(this.handleLinkHookCall(element,element.link,event)) return;
|
||||
if(this.openExternalLink(element.link, !isSHIFT(event) && !isCTRL(event) && !isMETA(event) && !isALT(event) ? element : undefined)) return;
|
||||
if(this.openExternalLink(element.link, !isSHIFT(event) && !isWinCTRLorMacCMD(event) && !isWinMETAorMacCTRL(event) && !isWinALTorMacOPT(event) ? element : undefined)) return;
|
||||
|
||||
//if element is type text and element has multiple links, then submit the element text to linkClick to trigger link suggester
|
||||
if(element.type === "text") {
|
||||
@@ -3927,7 +3942,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
if (
|
||||
element &&
|
||||
(this.plugin.settings.hoverPreviewWithoutCTRL ||
|
||||
isCTRL(event))
|
||||
isWinCTRLorMacCMD(event))
|
||||
) {
|
||||
this.lastMouseEvent = event;
|
||||
this.lastMouseEvent.ctrlKey = !(DEVICE.isIOS || DEVICE.isMacOS) || this.lastMouseEvent.ctrlKey;
|
||||
|
||||
@@ -400,6 +400,7 @@ const createImgElement = async (
|
||||
fheight: imgOrDiv.getAttribute("h"),
|
||||
style: [...Array.from(imgOrDiv.classList)],
|
||||
}, onCanvas);
|
||||
if(!newImg) return;
|
||||
parent.empty();
|
||||
if(!onCanvas) {
|
||||
newImg.style.maxHeight = imgMaxHeigth;
|
||||
|
||||
@@ -139,7 +139,8 @@ export const REG_BLOCK_REF_CLEAN = /[!"#$%&()*+,.:;<=>?@^`{|}~\/\[\]\\\r\n]/g;
|
||||
// /[!"#$%&()*+,.:;<=>?@^`{|}~\/\[\]\\]/g;
|
||||
// https://discord.com/channels/686053708261228577/989603365606531104/1000128926619816048
|
||||
// /\+|\/|~|=|%|\(|\)|{|}|,|&|\.|\$|!|\?|;|\[|]|\^|#|\*|<|>|&|@|\||\\|"|:|\s/g;
|
||||
export const IMAGE_TYPES = ["jpeg", "jpg", "png", "gif", "svg", "webp", "bmp", "ico"];
|
||||
export const IMAGE_TYPES = ["jpeg", "jpg", "png", "gif", "svg", "webp", "bmp", "ico", "jtif", "tif"];
|
||||
export const ANIMATED_IMAGE_TYPES = ["gif", "webp", "apng", "svg"];
|
||||
export const EXPORT_TYPES = ["svg", "dark.svg", "light.svg", "png", "dark.png", "light.png"];
|
||||
export const MAX_IMAGE_SIZE = 500;
|
||||
export const FRONTMATTER_KEY = "excalidraw-plugin";
|
||||
|
||||
@@ -8,6 +8,7 @@ export class EmbeddalbeMDFileCustomDataSettingsComponent {
|
||||
private contentEl: HTMLElement,
|
||||
private mdCustomData: EmbeddableMDCustomProps,
|
||||
private update?: Function,
|
||||
private isMDFile: boolean = true,
|
||||
) {
|
||||
if(!update) this.update = () => {};
|
||||
}
|
||||
@@ -33,16 +34,17 @@ export class EmbeddalbeMDFileCustomDataSettingsComponent {
|
||||
detailsDIV.style.display = this.mdCustomData.useObsidianDefaults ? "none" : "block";
|
||||
|
||||
const contentEl = detailsDIV
|
||||
new Setting(contentEl)
|
||||
.setName(t("ES_FILENAME_VISIBLE"))
|
||||
.addToggle(toggle =>
|
||||
toggle
|
||||
.setValue(this.mdCustomData.filenameVisible)
|
||||
.onChange(value => {
|
||||
this.mdCustomData.filenameVisible = value;
|
||||
})
|
||||
);
|
||||
|
||||
if(this.isMDFile) {
|
||||
new Setting(contentEl)
|
||||
.setName(t("ES_FILENAME_VISIBLE"))
|
||||
.addToggle(toggle =>
|
||||
toggle
|
||||
.setValue(this.mdCustomData.filenameVisible)
|
||||
.onChange(value => {
|
||||
this.mdCustomData.filenameVisible = value;
|
||||
})
|
||||
);
|
||||
}
|
||||
contentEl.createEl("h4",{text: t("ES_BACKGROUND_HEAD")});
|
||||
|
||||
let bgSetting: Setting;
|
||||
@@ -126,50 +128,52 @@ export class EmbeddalbeMDFileCustomDataSettingsComponent {
|
||||
})
|
||||
);
|
||||
|
||||
contentEl.createEl("h4",{text: t("ES_BORDER_HEAD")});
|
||||
let borderSetting: Setting;
|
||||
if(this.isMDFile) {
|
||||
contentEl.createEl("h4",{text: t("ES_BORDER_HEAD")});
|
||||
let borderSetting: Setting;
|
||||
|
||||
new Setting(contentEl)
|
||||
.setName(t("ES_BORDER_MATCH_ELEMENT"))
|
||||
.addToggle(toggle =>
|
||||
toggle
|
||||
.setValue(this.mdCustomData.borderMatchElement)
|
||||
.onChange(value => {
|
||||
this.mdCustomData.borderMatchElement = value;
|
||||
if(value) {
|
||||
borderSetting.settingEl.style.display = "none";
|
||||
} else {
|
||||
borderSetting.settingEl.style.display = "";
|
||||
}
|
||||
this.update();
|
||||
})
|
||||
);
|
||||
|
||||
borderSetting = new Setting(contentEl)
|
||||
.setName(t("ES_BORDER_COLOR"))
|
||||
.addColorPicker(colorPicker =>
|
||||
colorPicker
|
||||
.setValue(this.mdCustomData.borderColor)
|
||||
.onChange((value) => {
|
||||
this.mdCustomData.borderColor = value;
|
||||
this.update();
|
||||
})
|
||||
);
|
||||
|
||||
borderSetting.settingEl.style.display = this.mdCustomData.borderMatchElement ? "none" : "";
|
||||
|
||||
const borderOpacitySetting = new Setting(contentEl)
|
||||
.setName(t("ES_BORDER_OPACITY"))
|
||||
.setDesc(opacity(this.mdCustomData.borderOpacity))
|
||||
.addSlider(slider =>
|
||||
slider
|
||||
.setLimits(0,100,5)
|
||||
.setValue(this.mdCustomData.borderOpacity)
|
||||
.onChange(value => {
|
||||
this.mdCustomData.borderOpacity = value;
|
||||
borderOpacitySetting.setDesc(opacity(value));
|
||||
this.update();
|
||||
})
|
||||
new Setting(contentEl)
|
||||
.setName(t("ES_BORDER_MATCH_ELEMENT"))
|
||||
.addToggle(toggle =>
|
||||
toggle
|
||||
.setValue(this.mdCustomData.borderMatchElement)
|
||||
.onChange(value => {
|
||||
this.mdCustomData.borderMatchElement = value;
|
||||
if(value) {
|
||||
borderSetting.settingEl.style.display = "none";
|
||||
} else {
|
||||
borderSetting.settingEl.style.display = "";
|
||||
}
|
||||
this.update();
|
||||
})
|
||||
);
|
||||
|
||||
borderSetting = new Setting(contentEl)
|
||||
.setName(t("ES_BORDER_COLOR"))
|
||||
.addColorPicker(colorPicker =>
|
||||
colorPicker
|
||||
.setValue(this.mdCustomData.borderColor)
|
||||
.onChange((value) => {
|
||||
this.mdCustomData.borderColor = value;
|
||||
this.update();
|
||||
})
|
||||
);
|
||||
|
||||
borderSetting.settingEl.style.display = this.mdCustomData.borderMatchElement ? "none" : "";
|
||||
|
||||
const borderOpacitySetting = new Setting(contentEl)
|
||||
.setName(t("ES_BORDER_OPACITY"))
|
||||
.setDesc(opacity(this.mdCustomData.borderOpacity))
|
||||
.addSlider(slider =>
|
||||
slider
|
||||
.setLimits(0,100,5)
|
||||
.setValue(this.mdCustomData.borderOpacity)
|
||||
.onChange(value => {
|
||||
this.mdCustomData.borderOpacity = value;
|
||||
borderOpacitySetting.setDesc(opacity(value));
|
||||
this.update();
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import { getNewUniqueFilepath, getPathWithoutExtension, splitFolderAndFilename }
|
||||
import { addAppendUpdateCustomData, fragWithHTML } from "src/utils/Utils";
|
||||
import { getYouTubeStartAt, isValidYouTubeStart, isYouTube, updateYouTubeStartTime } from "src/utils/YoutTubeUtils";
|
||||
import { EmbeddalbeMDFileCustomDataSettingsComponent } from "./EmbeddableMDFileCustomDataSettingsComponent";
|
||||
import { isCTRL } from "src/utils/ModifierkeyHelper";
|
||||
import { isWinCTRLorMacCMD } from "src/utils/ModifierkeyHelper";
|
||||
import { ExcalidrawImperativeAPI } from "@zsviczian/excalidraw/types/types";
|
||||
|
||||
export type EmbeddableMDCustomProps = {
|
||||
@@ -32,6 +32,8 @@ export class EmbeddableSettings extends Modal {
|
||||
private isYouTube: boolean;
|
||||
private youtubeStart: string = null;
|
||||
private isMDFile: boolean;
|
||||
private notExcalidrawIsInternal: boolean;
|
||||
private isLocalURI: boolean;
|
||||
private mdCustomData: EmbeddableMDCustomProps;
|
||||
private onKeyDown: (ev: KeyboardEvent) => void;
|
||||
|
||||
@@ -46,7 +48,9 @@ export class EmbeddableSettings extends Modal {
|
||||
this.ea.copyViewElementsToEAforEditing([this.element]);
|
||||
this.zoomValue = element.scale[0];
|
||||
this.isYouTube = isYouTube(this.element.link);
|
||||
this.isMDFile = this.file && this.file.extension === "md" && !this.view.plugin.isExcalidrawFile(this.file)
|
||||
this.notExcalidrawIsInternal = this.file && !this.view.plugin.isExcalidrawFile(this.file)
|
||||
this.isMDFile = this.file && this.file.extension === "md" && !this.view.plugin.isExcalidrawFile(this.file);
|
||||
this.isLocalURI = this.element.link.startsWith("file://");
|
||||
if(isYouTube) this.youtubeStart = getYouTubeStartAt(this.element.link);
|
||||
|
||||
this.mdCustomData = element.customData?.mdProps ?? view.plugin.settings.embeddableMarkdownDefaults;
|
||||
@@ -126,9 +130,9 @@ export class EmbeddableSettings extends Modal {
|
||||
)
|
||||
}
|
||||
|
||||
if(this.isMDFile) {
|
||||
if(this.isMDFile || this.notExcalidrawIsInternal) {
|
||||
this.contentEl.createEl("h3",{text: t("ES_EMBEDDABLE_SETTINGS")});
|
||||
new EmbeddalbeMDFileCustomDataSettingsComponent(this.contentEl,this.mdCustomData).render();
|
||||
new EmbeddalbeMDFileCustomDataSettingsComponent(this.contentEl,this.mdCustomData, undefined, this.isMDFile).render();
|
||||
}
|
||||
|
||||
new Setting(this.contentEl)
|
||||
@@ -150,7 +154,7 @@ export class EmbeddableSettings extends Modal {
|
||||
|
||||
|
||||
const onKeyDown = (ev: KeyboardEvent) => {
|
||||
if(isCTRL(ev) && ev.key === "Enter") {
|
||||
if(isWinCTRLorMacCMD(ev) && ev.key === "Enter") {
|
||||
this.applySettings();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { App, FuzzySuggestModal, TFile } from "obsidian";
|
||||
import { isALT, scaleToFullsizeModifier } from "src/utils/ModifierkeyHelper";
|
||||
import { fileURLToPath } from "url";
|
||||
import { scaleToFullsizeModifier } from "src/utils/ModifierkeyHelper";
|
||||
import { DEVICE, IMAGE_TYPES, REG_LINKINDEX_INVALIDCHARS } from "../constants/constants";
|
||||
import ExcalidrawView from "../ExcalidrawView";
|
||||
import { t } from "../lang/helpers";
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
import { App, FuzzySuggestModal, TFile } from "obsidian";
|
||||
import { REG_LINKINDEX_INVALIDCHARS } from "../constants/constants";
|
||||
import { t } from "../lang/helpers";
|
||||
import ExcalidrawPlugin from "src/main";
|
||||
import { getLink } from "src/utils/FileUtils";
|
||||
|
||||
export class InsertLinkDialog extends FuzzySuggestModal<TFile> {
|
||||
public app: App;
|
||||
private addText: Function;
|
||||
private drawingPath: string;
|
||||
|
||||
constructor(app: App) {
|
||||
super(app);
|
||||
this.app = app;
|
||||
constructor(private plugin: ExcalidrawPlugin) {
|
||||
super(plugin.app);
|
||||
this.app = plugin.app;
|
||||
this.limit = 20;
|
||||
this.setInstructions([
|
||||
{
|
||||
@@ -45,7 +47,8 @@ export class InsertLinkDialog extends FuzzySuggestModal<TFile> {
|
||||
true,
|
||||
);
|
||||
}
|
||||
this.addText(`[[${filepath + (item.alias ? `|${item.alias}` : "")}]]`, filepath, item.alias);
|
||||
const link = getLink(this.plugin,{embed: false, path: filepath, alias: item.alias});
|
||||
this.addText(getLink(this.plugin,{embed: false, path: filepath, alias: item.alias}), filepath, item.alias);
|
||||
}
|
||||
|
||||
public start(drawingPath: string, addText: Function) {
|
||||
|
||||
@@ -17,6 +17,23 @@ 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://cdn.ko-fi.com/cdn/kofi3.png?v=3" height=45></a></div>
|
||||
`,
|
||||
"2.0.5":`
|
||||
<div class="excalidraw-videoWrapper"><div>
|
||||
<iframe src="https://www.youtube.com/embed/kp1K7GRrE6E" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
</div></div>
|
||||
|
||||
# Fixed
|
||||
- Scaled-resizing a sticky note (SHIFT+resize) caused Excalidraw to choke on slower devices
|
||||
- Improved plugin performance focusing on minimizing Excalidraw's effect on Obsidian overall
|
||||
- Images embedded with a URL often did not show up in image exports, hopefully, the issue will less frequently occur in the future.
|
||||
- Local file URL now follows Obsidian standard - making it easier to navigate in Markdown view mode.
|
||||
|
||||
# New
|
||||
- In plugin settings, under "Startup Script", the button now opens the startup script if it already exists.
|
||||
- Partial support for animated GIFs (will not show up in image exports, but can be added as interactive embeddables)
|
||||
- Configurable modifier keys for link click action and drag&drop actions.
|
||||
- Improved support for drag&drop from your local drive and embedding of files external to Excalidraw.
|
||||
`,
|
||||
"2.0.4":`
|
||||
<div class="excalidraw-videoWrapper"><div>
|
||||
<iframe src="https://www.youtube.com/embed/A1vrSGBbWgo" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
|
||||
97
src/dialogs/ModifierKeySettings.ts
Normal file
97
src/dialogs/ModifierKeySettings.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import { Setting } from "obsidian";
|
||||
import { DEVICE } from "src/constants/constants";
|
||||
import { t } from "src/lang/helpers";
|
||||
import { ModifierKeySet, ModifierSetType, modifierKeyTooltipMessages } from "src/utils/ModifierkeyHelper";
|
||||
|
||||
type ModifierKeyCategories = Partial<{
|
||||
[modifierSetType in ModifierSetType]: string;
|
||||
}>;
|
||||
|
||||
const CATEGORIES: ModifierKeyCategories = {
|
||||
WebBrowserDragAction: t("WEB_BROWSER_DRAG_ACTION"),
|
||||
LocalFileDragAction: t("LOCAL_FILE_DRAG_ACTION"),
|
||||
InternalDragAction: t("INTERNAL_DRAG_ACTION"),
|
||||
LinkClickAction: t("PANE_TARGET"),
|
||||
};
|
||||
|
||||
export class ModifierKeySettingsComponent {
|
||||
private isMacOS: boolean;
|
||||
|
||||
constructor(
|
||||
private contentEl: HTMLElement,
|
||||
private modifierKeyConfig: {
|
||||
Mac: Record<string, ModifierKeySet>;
|
||||
Win: Record<string, ModifierKeySet>;
|
||||
},
|
||||
private update?: Function,
|
||||
) {
|
||||
this.isMacOS = (DEVICE.isMacOS || DEVICE.isIOS);
|
||||
}
|
||||
|
||||
render() {
|
||||
const platform = this.isMacOS ? "Mac" : "Win";
|
||||
const modifierKeysConfig = this.modifierKeyConfig[platform];
|
||||
|
||||
Object.entries(CATEGORIES).forEach(([modifierSetType, label]) => {
|
||||
const detailsEl = this.contentEl.createEl("details");
|
||||
detailsEl.createEl("summary", {
|
||||
text: label,
|
||||
cls: "excalidraw-setting-h4",
|
||||
});
|
||||
|
||||
const modifierKeys = modifierKeysConfig[modifierSetType];
|
||||
detailsEl.createDiv({
|
||||
//@ts-ignore
|
||||
text: t("DEFAULT_ACTION_DESC") + modifierKeyTooltipMessages()[modifierSetType][modifierKeys.defaultAction],
|
||||
cls: "setting-item-description"
|
||||
});
|
||||
Object.entries(modifierKeys.rules).forEach(([action, rule]) => {
|
||||
const setting = new Setting(detailsEl)
|
||||
//@ts-ignore
|
||||
.setName(modifierKeyTooltipMessages()[modifierSetType][rule.result]);
|
||||
|
||||
setting.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(rule.shift)
|
||||
.setTooltip("SHIFT")
|
||||
.onChange((value) => {
|
||||
rule.shift = value;
|
||||
this.update();
|
||||
})
|
||||
);
|
||||
setting.addToggle((toggle) => {
|
||||
toggle
|
||||
.setValue(rule.ctrl_cmd)
|
||||
.setTooltip(this.isMacOS ? "CMD" : "CTRL")
|
||||
.onChange((value) => {
|
||||
rule.ctrl_cmd = value;
|
||||
this.update();
|
||||
})
|
||||
if(this.isMacOS && modifierSetType !== "LinkClickAction") {
|
||||
toggle.setDisabled(true);
|
||||
toggle.toggleEl.style.opacity = "0.5";
|
||||
}
|
||||
});
|
||||
|
||||
setting.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(rule.alt_opt)
|
||||
.setTooltip(this.isMacOS ? "OPT" : "ALT")
|
||||
.onChange((value) => {
|
||||
rule.alt_opt = value;
|
||||
this.update();
|
||||
})
|
||||
);
|
||||
setting.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(rule.meta_ctrl)
|
||||
.setTooltip(this.isMacOS ? "CTRL" : "META")
|
||||
.onChange((value) => {
|
||||
rule.meta_ctrl = value;
|
||||
this.update();
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ import ExcalidrawPlugin from "../main";
|
||||
import { escapeRegExp, sleep } from "../utils/Utils";
|
||||
import { getLeaf } from "../utils/ObsidianUtils";
|
||||
import { checkAndCreateFolder, splitFolderAndFilename } from "src/utils/FileUtils";
|
||||
import { KeyEvent, isCTRL } from "src/utils/ModifierkeyHelper";
|
||||
import { KeyEvent, isWinCTRLorMacCMD } from "src/utils/ModifierkeyHelper";
|
||||
import { t } from "src/lang/helpers";
|
||||
import { ExcalidrawElement, getEA } from "src";
|
||||
import { ExcalidrawAutomate } from "src/ExcalidrawAutomate";
|
||||
@@ -342,11 +342,11 @@ export class GenericInputPrompt extends Modal {
|
||||
private cancelClickCallback = () => this.cancel();
|
||||
|
||||
private keyDownCallback = (evt: KeyboardEvent) => {
|
||||
if ((evt.key === "Enter" && this.lines === 1) || (isCTRL(evt) && evt.key === "Enter")) {
|
||||
if ((evt.key === "Enter" && this.lines === 1) || (isWinCTRLorMacCMD(evt) && evt.key === "Enter")) {
|
||||
evt.preventDefault();
|
||||
this.submit();
|
||||
}
|
||||
if (this.displayEditorButtons && evt.key === "k" && isCTRL(evt)) {
|
||||
if (this.displayEditorButtons && evt.key === "k" && isWinCTRLorMacCMD(evt)) {
|
||||
evt.preventDefault();
|
||||
this.linkBtnClickCallback();
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import ExcalidrawView from "../ExcalidrawView";
|
||||
import ExcalidrawPlugin from "../main";
|
||||
import { Modal, Setting, TextComponent } from "obsidian";
|
||||
import { FileSuggestionModal } from "./FolderSuggester";
|
||||
import { IMAGE_TYPES, sceneCoordsToViewportCoords, viewportCoordsToSceneCoords, MAX_IMAGE_SIZE } from "src/constants/constants";
|
||||
import { IMAGE_TYPES, sceneCoordsToViewportCoords, viewportCoordsToSceneCoords, MAX_IMAGE_SIZE, ANIMATED_IMAGE_TYPES } from "src/constants/constants";
|
||||
import { insertEmbeddableToView, insertImageToView } from "src/utils/ExcalidrawViewUtils";
|
||||
import { getEA } from "src";
|
||||
import { InsertPDFModal } from "./InsertPDFModal";
|
||||
@@ -80,6 +80,7 @@ export class UniversalInsertFileModal extends Modal {
|
||||
const ea = this.plugin.ea;
|
||||
const isMarkdown = file && file.extension === "md" && !ea.isExcalidrawFile(file);
|
||||
const isImage = file && (IMAGE_TYPES.contains(file.extension) || ea.isExcalidrawFile(file));
|
||||
const isAnimatedImage = file && ANIMATED_IMAGE_TYPES.contains(file.extension);
|
||||
const isIFrame = file && !isImage;
|
||||
const isPDF = file && file.extension === "pdf";
|
||||
const isExcalidraw = file && ea.isExcalidrawFile(file);
|
||||
@@ -116,7 +117,7 @@ export class UniversalInsertFileModal extends Modal {
|
||||
actionImage.buttonEl.style.display = "none";
|
||||
}
|
||||
|
||||
if (isIFrame) {
|
||||
if (isIFrame || isAnimatedImage) {
|
||||
actionIFrame.buttonEl.style.display = "block";
|
||||
} else {
|
||||
actionIFrame.buttonEl.style.display = "none";
|
||||
|
||||
@@ -277,6 +277,12 @@ FILENAME_HEAD: "Filename",
|
||||
"the plugin will open it in a browser. " +
|
||||
"When Obsidian files change, the matching <code>[[link]]</code> in your drawings will also change. " +
|
||||
"If you don't want text accidentally changing in your drawings use <code>[[links|with aliases]]</code>.",
|
||||
DRAG_MODIFIER_NAME: "Link Click and Drag&Drop Modifier Keys",
|
||||
DRAG_MODIFIER_DESC: "Modifier key behavior when clicking links and dragging and dropping elements. " +
|
||||
"Excalidraw will not validate your configuration... pay attention to avoid conflicting settings. " +
|
||||
"These settings are different for Apple and non-Apple. If you use Obsidian on multiple platforms, you'll need to make the settings separately. "+
|
||||
"The toggles follow the order of " +
|
||||
(DEVICE.isIOS || DEVICE.isMacOS ? "SHIFT, CMD, OPT, CONTROL." : "SHIFT, CTRL, ALT, META (Windows key)."),
|
||||
ADJACENT_PANE_NAME: "Reuse adjacent pane",
|
||||
ADJACENT_PANE_DESC:
|
||||
`When ${labelCTRL()}+${labelALT()} clicking a link in Excalidraw, by default the plugin will open the link in a new pane. ` +
|
||||
@@ -650,5 +656,11 @@ FILENAME_HEAD: "Filename",
|
||||
PROMPT_BUTTON_INSERT_SPACE: "Insert space",
|
||||
PROMPT_BUTTON_INSERT_LINK: "Insert markdown link to file",
|
||||
PROMPT_BUTTON_UPPERCASE: "Uppercase",
|
||||
|
||||
|
||||
//ModifierKeySettings
|
||||
WEB_BROWSER_DRAG_ACTION: "Web Browser Drag Action",
|
||||
LOCAL_FILE_DRAG_ACTION: "OS Local File Drag Action",
|
||||
INTERNAL_DRAG_ACTION: "Obsidian Internal Drag Action",
|
||||
PANE_TARGET: "Link click behavior",
|
||||
DEFAULT_ACTION_DESC: "In case none of the combinations apply the default action for this group is: ",
|
||||
};
|
||||
|
||||
20
src/main.ts
20
src/main.ts
@@ -80,6 +80,7 @@ import {
|
||||
getDrawingFilename,
|
||||
getEmbedFilename,
|
||||
getIMGFilename,
|
||||
getLink,
|
||||
getNewUniqueFilepath,
|
||||
} from "./utils/FileUtils";
|
||||
import {
|
||||
@@ -791,7 +792,7 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
|
||||
private registerCommands() {
|
||||
this.openDialog = new OpenFileDialog(this.app, this);
|
||||
this.insertLinkDialog = new InsertLinkDialog(this.app);
|
||||
this.insertLinkDialog = new InsertLinkDialog(this);
|
||||
this.insertCommandDialog = new InsertCommandDialog(this.app);
|
||||
this.insertImageDialog = new InsertImageDialog(this);
|
||||
this.importSVGDialog = new ImportSVGDialog(this);
|
||||
@@ -1978,7 +1979,7 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
|
||||
private popScope: Function = null;
|
||||
private registerEventListeners() {
|
||||
const self = this;
|
||||
const self: ExcalidrawPlugin = this;
|
||||
this.app.workspace.onLayoutReady(async () => {
|
||||
const onPasteHandler = (
|
||||
evt: ClipboardEvent,
|
||||
@@ -2008,18 +2009,15 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
if(sourceFile && imageFile && imageFile instanceof TFile) {
|
||||
path = self.app.metadataCache.fileToLinktext(imageFile,sourceFile.path);
|
||||
}
|
||||
//@ts-ignore
|
||||
editor.insertText(self.getLink({path}));
|
||||
editor.insertText(getLink(self, {path}));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (element.type === "text") {
|
||||
//@ts-ignore
|
||||
editor.insertText(element.text);
|
||||
return;
|
||||
}
|
||||
if (element.link) {
|
||||
//@ts-ignore
|
||||
editor.insertText(`${element.link}`);
|
||||
return;
|
||||
}
|
||||
@@ -2485,14 +2483,6 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
})
|
||||
}
|
||||
|
||||
public getLink(
|
||||
{ embed = true, path, alias }: { embed?: boolean; path: string; alias?: string }
|
||||
):string {
|
||||
return this.settings.embedWikiLink
|
||||
? `${embed ? "!" : ""}[[${path}${alias ? `|${alias}` : ""}]]`
|
||||
: `${embed ? "!" : ""}[${alias ?? ""}](${encodeURI(path)})`
|
||||
}
|
||||
|
||||
public async embedDrawing(file: TFile) {
|
||||
const activeView = this.app.workspace.getActiveViewOfType(MarkdownView);
|
||||
if (activeView && activeView.file) {
|
||||
@@ -2506,7 +2496,7 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
//embed Excalidraw
|
||||
if (this.settings.embedType === "excalidraw") {
|
||||
editor.replaceSelection(
|
||||
this.getLink({path: excalidrawRelativePath}),
|
||||
getLink(this, {path: excalidrawRelativePath}),
|
||||
);
|
||||
editor.focus();
|
||||
return;
|
||||
|
||||
@@ -11,7 +11,7 @@ import { ReleaseNotes } from "../dialogs/ReleaseNotes";
|
||||
import { ScriptIconMap } from "../Scripts";
|
||||
import { ScriptInstallPrompt } from "src/dialogs/ScriptInstallPrompt";
|
||||
import { ExcalidrawImperativeAPI } from "@zsviczian/excalidraw/types/types";
|
||||
import { isALT, isCTRL, isSHIFT } from "src/utils/ModifierkeyHelper";
|
||||
import { isWinALTorMacOPT, isWinCTRLorMacCMD, isSHIFT } from "src/utils/ModifierkeyHelper";
|
||||
import { InsertPDFModal } from "src/dialogs/InsertPDFModal";
|
||||
import { ExportDialog } from "src/dialogs/ExportDialog";
|
||||
|
||||
@@ -379,7 +379,7 @@ export class ToolsPanel extends React.Component<PanelProps, PanelState> {
|
||||
new Notice("Taskbone OCR is not enabled. Please go to plugins settings to enable it.",4000);
|
||||
return;
|
||||
}
|
||||
this.props.view.plugin.taskbone.getTextForView(this.props.view, isCTRL(e));
|
||||
this.props.view.plugin.taskbone.getTextForView(this.props.view, isWinCTRLorMacCMD(e));
|
||||
}}
|
||||
icon={ICONS.ocr}
|
||||
view={this.props.view}
|
||||
@@ -504,7 +504,7 @@ export class ToolsPanel extends React.Component<PanelProps, PanelState> {
|
||||
key={"latex"}
|
||||
title={t("INSERT_LATEX")}
|
||||
action={(e) => {
|
||||
if(isALT(e)) {
|
||||
if(isWinALTorMacOPT(e)) {
|
||||
this.props.view.openExternalLink("https://youtu.be/r08wk-58DPk");
|
||||
return;
|
||||
}
|
||||
@@ -531,12 +531,12 @@ export class ToolsPanel extends React.Component<PanelProps, PanelState> {
|
||||
key={"link-to-element"}
|
||||
title={t("INSERT_LINK_TO_ELEMENT")}
|
||||
action={(e:React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
||||
if(isALT(e)) {
|
||||
if(isWinALTorMacOPT(e)) {
|
||||
this.props.view.openExternalLink("https://youtu.be/yZQoJg2RCKI");
|
||||
return;
|
||||
}
|
||||
this.props.view.copyLinkToSelectedElementToClipboard(
|
||||
isCTRL(e) ? "group=" : (isSHIFT(e) ? "area=" : "")
|
||||
isWinCTRLorMacCMD(e) ? "group=" : (isSHIFT(e) ? "area=" : "")
|
||||
);
|
||||
}}
|
||||
icon={ICONS.copyElementLink}
|
||||
|
||||
@@ -3,7 +3,6 @@ import {
|
||||
ButtonComponent,
|
||||
DropdownComponent,
|
||||
normalizePath,
|
||||
Notice,
|
||||
PluginSettingTab,
|
||||
Setting,
|
||||
TextComponent,
|
||||
@@ -32,6 +31,8 @@ import { ConfirmationPrompt } from "./dialogs/Prompt";
|
||||
import { EmbeddableMDCustomProps } from "./dialogs/EmbeddableSettings";
|
||||
import { EmbeddalbeMDFileCustomDataSettingsComponent } from "./dialogs/EmbeddableMDFileCustomDataSettingsComponent";
|
||||
import { startupScript } from "./constants/starutpscript";
|
||||
import { ModifierKeySet, ModifierSetType } from "./utils/ModifierkeyHelper";
|
||||
import { ModifierKeySettingsComponent } from "./dialogs/ModifierKeySettings";
|
||||
|
||||
export interface ExcalidrawSettings {
|
||||
folder: string;
|
||||
@@ -159,6 +160,10 @@ export interface ExcalidrawSettings {
|
||||
openAIAPIToken: string,
|
||||
openAIDefaultTextModel: string,
|
||||
openAIDefaultVisionModel: string,
|
||||
modifierKeyConfig: {
|
||||
Mac: Record<ModifierSetType, ModifierKeySet>,
|
||||
Win: Record<ModifierSetType, ModifierKeySet>,
|
||||
}
|
||||
}
|
||||
|
||||
declare const PLUGIN_VERSION:string;
|
||||
@@ -305,6 +310,86 @@ export const DEFAULT_SETTINGS: ExcalidrawSettings = {
|
||||
openAIAPIToken: "",
|
||||
openAIDefaultTextModel: "gpt-3.5-turbo-1106",
|
||||
openAIDefaultVisionModel: "gpt-4-vision-preview",
|
||||
modifierKeyConfig: {
|
||||
Mac: {
|
||||
LocalFileDragAction:{
|
||||
defaultAction: "image-import",
|
||||
rules: [
|
||||
{ shift: false, ctrl_cmd: false, alt_opt: false, meta_ctrl: false, result: "image-import" },
|
||||
{ shift: true , ctrl_cmd: false, alt_opt: true , meta_ctrl: false, result: "link" },
|
||||
{ shift: true , ctrl_cmd: false, alt_opt: false, meta_ctrl: false, result: "image-url" },
|
||||
{ shift: false, ctrl_cmd: false, alt_opt: true , meta_ctrl: false, result: "embeddable" },
|
||||
],
|
||||
},
|
||||
WebBrowserDragAction: {
|
||||
defaultAction: "image-url",
|
||||
rules: [
|
||||
{ shift: false, ctrl_cmd: false, alt_opt: false, meta_ctrl: false, result: "image-url" },
|
||||
{ shift: true , ctrl_cmd: false, alt_opt: true , meta_ctrl: false, result: "link" },
|
||||
{ shift: false, ctrl_cmd: false, alt_opt: true , meta_ctrl: false, result: "embeddable" },
|
||||
{ shift: true , ctrl_cmd: false, alt_opt: false, meta_ctrl: false, result: "image-import" },
|
||||
],
|
||||
},
|
||||
InternalDragAction: {
|
||||
defaultAction: "link",
|
||||
rules: [
|
||||
{ shift: false, ctrl_cmd: false, alt_opt: false, meta_ctrl: false, result: "link" },
|
||||
{ shift: false, ctrl_cmd: false, alt_opt: false, meta_ctrl: true , result: "embeddable" },
|
||||
{ shift: true , ctrl_cmd: false, alt_opt: false, meta_ctrl: false, result: "image" },
|
||||
{ shift: true , ctrl_cmd: false, alt_opt: false, meta_ctrl: true , result: "image-fullsize" },
|
||||
],
|
||||
},
|
||||
LinkClickAction: {
|
||||
defaultAction: "new-tab",
|
||||
rules: [
|
||||
{ shift: false, ctrl_cmd: false, alt_opt: false, meta_ctrl: false, result: "active-pane" },
|
||||
{ shift: false, ctrl_cmd: true , alt_opt: false, meta_ctrl: false, result: "new-tab" },
|
||||
{ shift: false, ctrl_cmd: true , alt_opt: true , meta_ctrl: false, result: "new-pane" },
|
||||
{ shift: true , ctrl_cmd: true , alt_opt: true , meta_ctrl: false, result: "popout-window" },
|
||||
{ shift: false, ctrl_cmd: true , alt_opt: false, meta_ctrl: true , result: "md-properties" },
|
||||
],
|
||||
},
|
||||
},
|
||||
Win: {
|
||||
LocalFileDragAction:{
|
||||
defaultAction: "image-import",
|
||||
rules: [
|
||||
{ shift: false, ctrl_cmd: false, alt_opt: false, meta_ctrl: false, result: "image-import" },
|
||||
{ shift: false, ctrl_cmd: true , alt_opt: false, meta_ctrl: false, result: "link" },
|
||||
{ shift: true , ctrl_cmd: false, alt_opt: false, meta_ctrl: false, result: "image-url" },
|
||||
{ shift: true , ctrl_cmd: true , alt_opt: false, meta_ctrl: false, result: "embeddable" },
|
||||
],
|
||||
},
|
||||
WebBrowserDragAction: {
|
||||
defaultAction: "image-url",
|
||||
rules: [
|
||||
{ shift: false, ctrl_cmd: false, alt_opt: false, meta_ctrl: false, result: "image-url" },
|
||||
{ shift: false, ctrl_cmd: true , alt_opt: false, meta_ctrl: false, result: "link" },
|
||||
{ shift: true , ctrl_cmd: true , alt_opt: false, meta_ctrl: false, result: "embeddable" },
|
||||
{ shift: true , ctrl_cmd: false, alt_opt: false, meta_ctrl: false, result: "image-import" },
|
||||
],
|
||||
},
|
||||
InternalDragAction: {
|
||||
defaultAction: "link",
|
||||
rules: [
|
||||
{ shift: false, ctrl_cmd: false, alt_opt: false, meta_ctrl: false, result: "link" },
|
||||
{ shift: true , ctrl_cmd: true , alt_opt: false, meta_ctrl: false, result: "embeddable" },
|
||||
{ shift: true , ctrl_cmd: false, alt_opt: false, meta_ctrl: false, result: "image" },
|
||||
{ shift: false, ctrl_cmd: true , alt_opt: true , meta_ctrl: false, result: "image-fullsize" },
|
||||
],
|
||||
},
|
||||
LinkClickAction: {
|
||||
defaultAction: "new-tab",
|
||||
rules: [
|
||||
{ shift: false, ctrl_cmd: false, alt_opt: false, meta_ctrl: false, result: "active-pane" },
|
||||
{ shift: false, ctrl_cmd: true , alt_opt: false, meta_ctrl: false, result: "new-tab" },
|
||||
{ shift: false, ctrl_cmd: true , alt_opt: true , meta_ctrl: false, result: "new-pane" },
|
||||
{ shift: true , ctrl_cmd: true , alt_opt: true , meta_ctrl: false, result: "popout-window" },
|
||||
{ shift: false, ctrl_cmd: true , alt_opt: false, meta_ctrl: true , result: "md-properties" },
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
export class ExcalidrawSettingTab extends PluginSettingTab {
|
||||
@@ -979,6 +1064,18 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
|
||||
el.innerText = ` ${this.plugin.settings.laserSettings.DECAY_LENGTH.toString()}`;
|
||||
});
|
||||
|
||||
detailsEl = displayDetailsEl.createEl("details");
|
||||
detailsEl.createEl("summary", {
|
||||
text: t("DRAG_MODIFIER_NAME"),
|
||||
cls: "excalidraw-setting-h3",
|
||||
});
|
||||
detailsEl.createDiv({ text: t("DRAG_MODIFIER_DESC"), cls: "setting-item-description" });
|
||||
|
||||
new ModifierKeySettingsComponent(
|
||||
detailsEl,
|
||||
this.plugin.settings.modifierKeyConfig,
|
||||
this.applySettingsUpdate,
|
||||
).render();
|
||||
|
||||
// ------------------------------------------------
|
||||
// Links and Transclusions
|
||||
|
||||
9
src/types.d.ts
vendored
9
src/types.d.ts
vendored
@@ -49,4 +49,13 @@ declare module "obsidian" {
|
||||
ctx?: any,
|
||||
): EventRef;
|
||||
}
|
||||
interface DataAdapter {
|
||||
url: {
|
||||
pathToFileURL(path: string): URL;
|
||||
},
|
||||
basePath: string;
|
||||
}
|
||||
interface Editor {
|
||||
insertText(data: string): void;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
import { MAX_IMAGE_SIZE, IMAGE_TYPES } from "src/constants/constants";
|
||||
import { MAX_IMAGE_SIZE, IMAGE_TYPES, ANIMATED_IMAGE_TYPES } from "src/constants/constants";
|
||||
import { TFile } from "obsidian";
|
||||
import { ExcalidrawAutomate } from "src/ExcalidrawAutomate";
|
||||
import { REGEX_LINK, REG_LINKINDEX_HYPERLINK } from "src/ExcalidrawData";
|
||||
@@ -34,7 +34,7 @@ export const insertEmbeddableToView = async (
|
||||
ea.clear();
|
||||
ea.style.strokeColor = "transparent";
|
||||
ea.style.backgroundColor = "transparent";
|
||||
if(file && IMAGE_TYPES.contains(file.extension) || ea.isExcalidrawFile(file)) {
|
||||
if(file && (IMAGE_TYPES.contains(file.extension) || ea.isExcalidrawFile(file)) && !ANIMATED_IMAGE_TYPES.contains(file.extension)) {
|
||||
return await insertImageToView(ea, position, file);
|
||||
} else {
|
||||
const id = ea.addEmbeddable(
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
import { DataURL } from "@zsviczian/excalidraw/types/types";
|
||||
import { loadPdfJs, normalizePath, Notice, requestUrl, RequestUrlResponse, TAbstractFile, TFile, TFolder, Vault } from "obsidian";
|
||||
import { URLFETCHTIMEOUT } from "src/constants/constants";
|
||||
import { MimeType } from "src/EmbeddedFileLoader";
|
||||
import { IMAGE_MIME_TYPES, MimeType } from "src/EmbeddedFileLoader";
|
||||
import { ExcalidrawSettings } from "src/settings";
|
||||
import { errorlog, getDataURL } from "./Utils";
|
||||
import ExcalidrawPlugin from "src/main";
|
||||
|
||||
/**
|
||||
* Splits a full path including a folderpath and a filename into separate folderpath and filename components
|
||||
* @param filepath
|
||||
*/
|
||||
type ImageExtension = keyof typeof IMAGE_MIME_TYPES;
|
||||
|
||||
export function splitFolderAndFilename(filepath: string): {
|
||||
folderpath: string;
|
||||
filename: string;
|
||||
basename: string;
|
||||
extension: string;
|
||||
} {
|
||||
const lastIndex = filepath.lastIndexOf("/");
|
||||
const filename = lastIndex == -1 ? filepath : filepath.substring(lastIndex + 1);
|
||||
@@ -21,6 +24,7 @@ export function splitFolderAndFilename(filepath: string): {
|
||||
folderpath: normalizePath(filepath.substring(0, lastIndex)),
|
||||
filename,
|
||||
basename: filename.replace(/\.[^/.]+$/, ""),
|
||||
extension: filename.substring(filename.lastIndexOf(".") + 1),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -155,15 +159,10 @@ export const getURLImageExtension = (url: string):string => {
|
||||
}
|
||||
|
||||
export const getMimeType = (extension: string):MimeType => {
|
||||
if(IMAGE_MIME_TYPES.hasOwnProperty(extension)) {
|
||||
return IMAGE_MIME_TYPES[extension as ImageExtension];
|
||||
};
|
||||
switch (extension) {
|
||||
case "png": return "image/png";
|
||||
case "jpeg": return "image/jpeg";
|
||||
case "jpg": return "image/jpeg";
|
||||
case "gif": return "image/gif";
|
||||
case "webp": return "image/webp";
|
||||
case "bmp": return "image/bmp";
|
||||
case "ico": return "image/x-icon";
|
||||
case "svg": return "image/svg+xml";
|
||||
case "md": return "image/svg+xml";
|
||||
default: return "application/octet-stream";
|
||||
}
|
||||
@@ -326,4 +325,40 @@ export const readLocalFileBinary = async (filePath:string): Promise<ArrayBuffer>
|
||||
export const getPathWithoutExtension = (f:TFile): string => {
|
||||
if(!f) return null;
|
||||
return f.path.substring(0, f.path.lastIndexOf("."));
|
||||
}
|
||||
|
||||
const VAULT_BASE_URL = app.vault.adapter.url.pathToFileURL(app.vault.adapter.basePath).toString();
|
||||
export const getInternalLinkOrFileURLLink = (
|
||||
path: string, plugin:ExcalidrawPlugin, alias?: string, sourceFile?: TFile
|
||||
):{link: string, isInternal: boolean, file?: TFile, url?: string} => {
|
||||
const vault = plugin.app.vault;
|
||||
const fileURLString = vault.adapter.url.pathToFileURL(path).toString();
|
||||
if (fileURLString.startsWith(VAULT_BASE_URL)) {
|
||||
const internalPath = normalizePath(fileURLString.substring(VAULT_BASE_URL.length));
|
||||
const file = vault.getAbstractFileByPath(internalPath);
|
||||
if(file && file instanceof TFile) {
|
||||
const link = plugin.app.metadataCache.fileToLinktext(
|
||||
file,
|
||||
sourceFile?.path,
|
||||
true,
|
||||
);
|
||||
return {link: getLink(plugin, { embed: false, path: link, alias}), isInternal: true, file};
|
||||
};
|
||||
}
|
||||
return {link: `[${alias??""}](${fileURLString})`, isInternal: false, url: fileURLString};
|
||||
}
|
||||
|
||||
/**
|
||||
* get markdown or wiki link
|
||||
* @param plugin
|
||||
* @param param1: { embed = true, path, alias }
|
||||
* @returns
|
||||
*/
|
||||
export const getLink = (
|
||||
plugin: ExcalidrawPlugin,
|
||||
{ embed = true, path, alias }: { embed?: boolean; path: string; alias?: string }
|
||||
):string => {
|
||||
return plugin.settings.embedWikiLink
|
||||
? `${embed ? "!" : ""}[[${path}${alias ? `|${alias}` : ""}]]`
|
||||
: `${embed ? "!" : ""}[${alias ?? ""}](${encodeURI(path)})`
|
||||
}
|
||||
@@ -1,19 +1,88 @@
|
||||
import { DEVICE, isDarwin } from "src/constants/constants";
|
||||
import { DEVICE } from "src/constants/constants";
|
||||
import { ExcalidrawSettings } from "src/settings";
|
||||
export type ModifierKeys = {shiftKey:boolean, ctrlKey: boolean, metaKey: boolean, altKey: boolean};
|
||||
export type KeyEvent = PointerEvent | MouseEvent | KeyboardEvent | React.DragEvent | React.PointerEvent | React.MouseEvent | ModifierKeys;
|
||||
export type PaneTarget = "active-pane"|"new-pane"|"popout-window"|"new-tab"|"md-properties";
|
||||
export type ExternalDragAction = "insert-link"|"image-url"|"image-import"|"embeddable";
|
||||
export type LocalFileDragAction = "insert-link"|"image-uri"|"image-import";
|
||||
export type WebBrowserDragAction = "link"|"image-url"|"image-import"|"embeddable";
|
||||
export type LocalFileDragAction = "link"|"image-url"|"image-import"|"embeddable";
|
||||
export type InternalDragAction = "link"|"image"|"image-fullsize"|"embeddable";
|
||||
export type ModifierSetType = "WebBrowserDragAction" | "LocalFileDragAction" | "InternalDragAction" | "LinkClickAction";
|
||||
|
||||
type ModifierKey = {
|
||||
shift: boolean;
|
||||
ctrl_cmd: boolean;
|
||||
alt_opt: boolean;
|
||||
meta_ctrl: boolean;
|
||||
result: WebBrowserDragAction | LocalFileDragAction | InternalDragAction | PaneTarget;
|
||||
};
|
||||
|
||||
export type ModifierKeySet = {
|
||||
defaultAction: WebBrowserDragAction | LocalFileDragAction | InternalDragAction | PaneTarget;
|
||||
rules: ModifierKey[];
|
||||
};
|
||||
|
||||
export type ModifierKeyTooltipMessages = Partial<{
|
||||
[modifierSetType in ModifierSetType]: Partial<{
|
||||
[action in WebBrowserDragAction | LocalFileDragAction | InternalDragAction | PaneTarget]: string;
|
||||
}>;
|
||||
}>;
|
||||
|
||||
export const modifierKeyTooltipMessages = ():ModifierKeyTooltipMessages => {
|
||||
return {
|
||||
WebBrowserDragAction: {
|
||||
"image-import": "Import Image to Vault",
|
||||
"image-url": `Insert Image or YouTube Thumbnail with URL`,
|
||||
"link": "Insert Link",
|
||||
"embeddable": "Insert Interactive-Frame",
|
||||
// Add more messages for WebBrowserDragAction as needed
|
||||
},
|
||||
LocalFileDragAction: {
|
||||
"image-import": "Insert Image: import external or reuse existing if path in Vault",
|
||||
"image-url": `Insert Image: with local URI or internal-link if from Vault`,
|
||||
"link": "Insert Link: local URI or internal-link if from Vault",
|
||||
"embeddable": "Insert Interactive-Frame: local URI or internal-link if from Vault",
|
||||
},
|
||||
InternalDragAction: {
|
||||
"image": "Insert Image",
|
||||
"image-fullsize": "Insert Image @100%",
|
||||
"link": `Insert Link`,
|
||||
"embeddable": "Insert Interactive-Frame",
|
||||
},
|
||||
LinkClickAction: {
|
||||
"active-pane": "Open in current active window",
|
||||
"new-pane": "Open in a new adjacent window",
|
||||
"popout-window": "Open in a popout window",
|
||||
"new-tab": "Open in a new tab",
|
||||
"md-properties": "Show the Markdown image-properties dialog (only relevant if you have embedded a markdown document as an image)",
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
const processModifiers = (ev: KeyEvent, modifierType: ModifierSetType): WebBrowserDragAction | LocalFileDragAction | InternalDragAction | PaneTarget => {
|
||||
const settings:ExcalidrawSettings = window.ExcalidrawAutomate.plugin.settings;
|
||||
const keySet = ((DEVICE.isMacOS || DEVICE.isIOS) ? settings.modifierKeyConfig.Mac : settings.modifierKeyConfig.Win)[modifierType];
|
||||
for (const rule of keySet.rules) {
|
||||
const { shift, ctrl_cmd, alt_opt, meta_ctrl, result } = rule;
|
||||
if (
|
||||
(isSHIFT(ev) === shift) &&
|
||||
(isWinCTRLorMacCMD(ev) === ctrl_cmd) &&
|
||||
(isWinALTorMacOPT(ev) === alt_opt) &&
|
||||
(isWinMETAorMacCTRL(ev) === meta_ctrl)
|
||||
) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return keySet.defaultAction;
|
||||
}
|
||||
|
||||
export const labelCTRL = () => DEVICE.isIOS || DEVICE.isMacOS ? "CMD" : "CTRL";
|
||||
export const labelALT = () => DEVICE.isIOS || DEVICE.isMacOS ? "OPT" : "ALT";
|
||||
export const labelMETA = () => DEVICE.isIOS || DEVICE.isMacOS ? "CTRL" : (DEVICE.isWindows ? "WIN" : "META");
|
||||
export const labelSHIFT = () => "SHIFT";
|
||||
|
||||
export const isCTRL = (e:KeyEvent) => DEVICE.isIOS || DEVICE.isMacOS ? e.metaKey : e.ctrlKey;
|
||||
export const isALT = (e:KeyEvent) => e.altKey;
|
||||
export const isMETA = (e:KeyEvent) => DEVICE.isIOS || DEVICE.isMacOS ? e.ctrlKey : e.metaKey;
|
||||
export const isWinCTRLorMacCMD = (e:KeyEvent) => DEVICE.isIOS || DEVICE.isMacOS ? e.metaKey : e.ctrlKey;
|
||||
export const isWinALTorMacOPT = (e:KeyEvent) => e.altKey;
|
||||
export const isWinMETAorMacCTRL = (e:KeyEvent) => DEVICE.isIOS || DEVICE.isMacOS ? e.ctrlKey : e.metaKey;
|
||||
export const isSHIFT = (e:KeyEvent) => e.shiftKey;
|
||||
|
||||
export const setCTRL = (e:ModifierKeys, value: boolean): ModifierKeys => {
|
||||
@@ -39,50 +108,38 @@ export const setSHIFT = (e:ModifierKeys, value: boolean): ModifierKeys => {
|
||||
return e;
|
||||
}
|
||||
|
||||
export const mdPropModifier = (ev: KeyEvent): boolean => !isSHIFT(ev) && isCTRL(ev) && !isALT(ev) && isMETA(ev);
|
||||
export const scaleToFullsizeModifier = (ev: KeyEvent) =>
|
||||
( isSHIFT(ev) && !isCTRL(ev) && !isALT(ev) && isMETA(ev)) ||
|
||||
(!isSHIFT(ev) && isCTRL(ev) && isALT(ev) && !isMETA(ev));
|
||||
|
||||
export const linkClickModifierType = (ev: KeyEvent):PaneTarget => {
|
||||
if(isCTRL(ev) && !isALT(ev) && isSHIFT(ev) && !isMETA(ev)) return "active-pane";
|
||||
if(isCTRL(ev) && !isALT(ev) && !isSHIFT(ev) && !isMETA(ev)) return "new-tab";
|
||||
if(isCTRL(ev) && isALT(ev) && !isSHIFT(ev) && !isMETA(ev)) return "new-pane";
|
||||
if(DEVICE.isDesktop && isCTRL(ev) && isALT(ev) && isSHIFT(ev) && !isMETA(ev) ) return "popout-window";
|
||||
if(isCTRL(ev) && isALT(ev) && isSHIFT(ev) && !isMETA(ev)) return "new-tab";
|
||||
if(mdPropModifier(ev)) return "md-properties";
|
||||
return "active-pane";
|
||||
export const mdPropModifier = (ev: KeyEvent): boolean => !isSHIFT(ev) && isWinCTRLorMacCMD(ev) && !isWinALTorMacOPT(ev) && isWinMETAorMacCTRL(ev);
|
||||
export const scaleToFullsizeModifier = (ev: KeyEvent) => {
|
||||
const settings:ExcalidrawSettings = window.ExcalidrawAutomate.plugin.settings;
|
||||
const keySet = ((DEVICE.isMacOS || DEVICE.isIOS) ? settings.modifierKeyConfig.Mac : settings.modifierKeyConfig.Win )["InternalDragAction"];
|
||||
const rule = keySet.rules.find(r => r.result === "image-fullsize");
|
||||
if(!rule) return false;
|
||||
const { shift, ctrl_cmd, alt_opt, meta_ctrl, result } = rule;
|
||||
return (
|
||||
(isSHIFT(ev) === shift) &&
|
||||
(isWinCTRLorMacCMD(ev) === ctrl_cmd) &&
|
||||
(isWinALTorMacOPT(ev) === alt_opt) &&
|
||||
(isWinMETAorMacCTRL(ev) === meta_ctrl)
|
||||
);
|
||||
}
|
||||
|
||||
export const externalDragModifierType = (ev: KeyEvent):ExternalDragAction => {
|
||||
if(DEVICE.isWindows && isSHIFT(ev) && isCTRL(ev) && !isALT(ev) && !isMETA(ev)) return "embeddable";
|
||||
if(DEVICE.isMacOS && !isSHIFT(ev) && !isCTRL(ev) && isALT(ev) && !isMETA(ev)) return "embeddable";
|
||||
if(DEVICE.isWindows && !isSHIFT(ev) && isCTRL(ev) && !isALT(ev) && !isMETA(ev)) return "insert-link";
|
||||
if(DEVICE.isMacOS && isSHIFT(ev) && !isCTRL(ev) && isALT(ev) && !isMETA(ev)) return "insert-link";
|
||||
if( isSHIFT(ev) && !isCTRL(ev) && !isALT(ev) && !isMETA(ev)) return "image-import";
|
||||
if(DEVICE.isWindows && !isSHIFT(ev) && !isCTRL(ev) && isALT(ev) && !isMETA(ev)) return "image-import";
|
||||
return "image-url";
|
||||
export const linkClickModifierType = (ev: KeyEvent):PaneTarget => {
|
||||
const action = processModifiers(ev, "LinkClickAction") as PaneTarget;
|
||||
if(!DEVICE.isDesktop && action === "popout-window") return "active-pane";
|
||||
return action;
|
||||
}
|
||||
|
||||
export const webbrowserDragModifierType = (ev: KeyEvent):WebBrowserDragAction => {
|
||||
return processModifiers(ev, "WebBrowserDragAction") as WebBrowserDragAction;
|
||||
}
|
||||
|
||||
export const localFileDragModifierType = (ev: KeyEvent):LocalFileDragAction => {
|
||||
if(DEVICE.isWindows && isSHIFT(ev) && isCTRL(ev) && !isALT(ev) && !isMETA(ev)) return "image-uri";
|
||||
if(DEVICE.isMacOS && !isSHIFT(ev) && !isCTRL(ev) && isALT(ev) && !isMETA(ev)) return "image-uri";
|
||||
if(DEVICE.isWindows && !isSHIFT(ev) && isCTRL(ev) && !isALT(ev) && !isMETA(ev)) return "insert-link";
|
||||
if(DEVICE.isMacOS && isSHIFT(ev) && !isCTRL(ev) && isALT(ev) && !isMETA(ev)) return "insert-link";
|
||||
if( isSHIFT(ev) && !isCTRL(ev) && !isALT(ev) && !isMETA(ev)) return "image-import";
|
||||
if(DEVICE.isWindows && !isSHIFT(ev) && !isCTRL(ev) && isALT(ev) && !isMETA(ev)) return "image-import";
|
||||
return "image-import";
|
||||
return processModifiers(ev, "LocalFileDragAction") as LocalFileDragAction;
|
||||
}
|
||||
|
||||
|
||||
//https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/468
|
||||
export const internalDragModifierType = (ev: KeyEvent):InternalDragAction => {
|
||||
if( !(DEVICE.isIOS || DEVICE.isMacOS) && isSHIFT(ev) && isCTRL(ev) && !isALT(ev) && !isMETA(ev)) return "embeddable";
|
||||
if( (DEVICE.isIOS || DEVICE.isMacOS) && !isSHIFT(ev) && !isCTRL(ev) && !isALT(ev) && isMETA(ev)) return "embeddable";
|
||||
if( isSHIFT(ev) && !isCTRL(ev) && !isALT(ev) && !isMETA(ev)) return "image";
|
||||
if(!isSHIFT(ev) && isCTRL(ev) && !isALT(ev) && !isMETA(ev)) return "image";
|
||||
if(scaleToFullsizeModifier(ev)) return "image-fullsize";
|
||||
return "link";
|
||||
return processModifiers(ev, "InternalDragAction") as InternalDragAction;
|
||||
}
|
||||
|
||||
export const emulateCTRLClickForLinks = (e:KeyEvent) => {
|
||||
@@ -97,27 +154,23 @@ export const emulateCTRLClickForLinks = (e:KeyEvent) => {
|
||||
export const emulateKeysForLinkClick = (action: PaneTarget): ModifierKeys => {
|
||||
const ev = {shiftKey: false, ctrlKey: false, metaKey: false, altKey: false};
|
||||
if(!action) return ev;
|
||||
switch(action) {
|
||||
case "active-pane":
|
||||
setCTRL(ev, true);
|
||||
setSHIFT(ev, true);
|
||||
break;
|
||||
case "new-pane":
|
||||
setCTRL(ev, true);
|
||||
setALT(ev, true);
|
||||
break;
|
||||
case "popout-window":
|
||||
setCTRL(ev, true);
|
||||
setALT(ev, true);
|
||||
setSHIFT(ev, true);
|
||||
break;
|
||||
case "new-tab":
|
||||
setCTRL(ev, true);
|
||||
break;
|
||||
case "md-properties":
|
||||
setCTRL(ev, true);
|
||||
setMETA(ev, true);
|
||||
break;
|
||||
const platform = DEVICE.isMacOS || DEVICE.isIOS ? "Mac" : "Win";
|
||||
const settings:ExcalidrawSettings = window.ExcalidrawAutomate.plugin.settings;
|
||||
const modifierKeyConfig = settings.modifierKeyConfig;
|
||||
|
||||
const config = modifierKeyConfig[platform]?.LinkClickAction;
|
||||
|
||||
if (config) {
|
||||
const rule = config.rules.find(rule => rule.result === action);
|
||||
if (rule) {
|
||||
setCTRL(ev, rule.ctrl_cmd);
|
||||
setALT(ev, rule.alt_opt);
|
||||
setMETA(ev, rule.meta_ctrl);
|
||||
setSHIFT(ev, rule.shift);
|
||||
} else {
|
||||
const defaultAction = config.defaultAction as PaneTarget;
|
||||
return emulateKeysForLinkClick(defaultAction);
|
||||
}
|
||||
}
|
||||
return ev;
|
||||
}
|
||||
|
||||
28
styles.css
28
styles.css
@@ -504,3 +504,31 @@ hr.excalidraw-setting-hr {
|
||||
.excalidraw .canvas-node .ex-md-font-code {
|
||||
--font-text: "Cascadia";
|
||||
}
|
||||
|
||||
.excalidraw__embeddable-container .workspace-leaf,
|
||||
.excalidraw__embeddable-container .workspace-leaf .view-content {
|
||||
::-webkit-scrollbar,
|
||||
::-webkit-scrollbar-horizontal {
|
||||
display: none;
|
||||
}
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.excalidraw__embeddable-container .workspace-leaf-content .view-content {
|
||||
padding-left: 2px;
|
||||
padding-right: 2px;
|
||||
padding-top: 0px;
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
|
||||
.excalidraw__embeddable-container .workspace-leaf .view-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.excalidraw__embeddable-container .workspace-leaf-content .image-container,
|
||||
.excalidraw__embeddable-container .workspace-leaf-content .audio-container,
|
||||
.excalidraw__embeddable-container .workspace-leaf-content .video-container {
|
||||
display: flex;
|
||||
}
|
||||
Reference in New Issue
Block a user