diff --git a/ea-scripts/directory-info.json b/ea-scripts/directory-info.json index e09d92c..2d8cc8c 100644 --- a/ea-scripts/directory-info.json +++ b/ea-scripts/directory-info.json @@ -1 +1 @@ -[{"fname":"Mindmap connector.md","mtime":1658686599427},{"fname":"Mindmap connector.svg","mtime":1658686599427},{"fname":"Add Connector Point.md","mtime":1645305706000},{"fname":"Add Connector Point.svg","mtime":1645944722000},{"fname":"Add Link to Existing File and Open.md","mtime":1647807918345},{"fname":"Add Link to Existing File and Open.svg","mtime":1645964261000},{"fname":"Add Link to New Page and Open.md","mtime":1654168862138},{"fname":"Add Link to New Page and Open.svg","mtime":1645960639000},{"fname":"Add Next Step in Process.md","mtime":1645305706000},{"fname":"Add Next Step in Process.svg","mtime":1645960639000},{"fname":"Box Each Selected Groups.md","mtime":1645305706000},{"fname":"Box Each Selected Groups.svg","mtime":1645967510000},{"fname":"Box Selected Elements.md","mtime":1645305706000},{"fname":"Box Selected Elements.svg","mtime":1645960639000},{"fname":"Change shape of selected elements.md","mtime":1652701169236},{"fname":"Change shape of selected elements.svg","mtime":1645960775000},{"fname":"Connect elements.md","mtime":1645305706000},{"fname":"Connect elements.svg","mtime":1645960639000},{"fname":"Convert freedraw to line.md","mtime":1645305706000},{"fname":"Convert freedraw to line.svg","mtime":1645960639000},{"fname":"Convert selected text elements to sticky notes.md","mtime":1670169501383},{"fname":"Convert selected text elements to sticky notes.svg","mtime":1645960639000},{"fname":"Convert text to link with folder and alias.md","mtime":1641639819000},{"fname":"Convert text to link with folder and alias.svg","mtime":1645960639000},{"fname":"Copy Selected Element Styles to Global.md","mtime":1642232088000},{"fname":"Copy Selected Element Styles to Global.svg","mtime":1645960639000},{"fname":"Create new markdown file and embed into active drawing.md","mtime":1640866935000},{"fname":"Create new markdown file and embed into active drawing.svg","mtime":1645960639000},{"fname":"Darken background color.md","mtime":1663059051059},{"fname":"Darken background color.svg","mtime":1645960639000},{"fname":"Elbow connectors.md","mtime":1671126911490},{"fname":"Elbow connectors.svg","mtime":1645960639000},{"fname":"Expand rectangles horizontally keep text centered.md","mtime":1646563692000},{"fname":"Expand rectangles horizontally keep text centered.svg","mtime":1645967510000},{"fname":"Expand rectangles horizontally.md","mtime":1644950235000},{"fname":"Expand rectangles horizontally.svg","mtime":1645967510000},{"fname":"Expand rectangles vertically keep text centered.md","mtime":1646563692000},{"fname":"Expand rectangles vertically keep text centered.svg","mtime":1645967510000},{"fname":"Expand rectangles vertically.md","mtime":1658686599427},{"fname":"Expand rectangles vertically.svg","mtime":1645967510000},{"fname":"Fixed horizontal distance between centers.md","mtime":1646743234000},{"fname":"Fixed horizontal distance between centers.svg","mtime":1645960639000},{"fname":"Fixed inner distance.md","mtime":1646743234000},{"fname":"Fixed inner distance.svg","mtime":1645960639000},{"fname":"Fixed spacing.md","mtime":1646743234000},{"fname":"Fixed spacing.svg","mtime":1645967510000},{"fname":"Fixed vertical distance between centers.md","mtime":1646743234000},{"fname":"Fixed vertical distance between centers.svg","mtime":1645967510000},{"fname":"Fixed vertical distance.md","mtime":1646743234000},{"fname":"Fixed vertical distance.svg","mtime":1645967510000},{"fname":"Lighten background color.md","mtime":1663059051059},{"fname":"Lighten background color.svg","mtime":1645959546000},{"fname":"Modify background color opacity.md","mtime":1644924415000},{"fname":"Modify background color opacity.svg","mtime":1645944722000},{"fname":"Normalize Selected Arrows.md","mtime":1670403743278},{"fname":"Normalize Selected Arrows.svg","mtime":1645960639000},{"fname":"Organic Line.md","mtime":1672920172531},{"fname":"Organic Line.svg","mtime":1645964261000},{"fname":"README.md","mtime":1645175700000},{"fname":"Repeat Elements.md","mtime":1663059051059},{"fname":"Repeat Elements.svg","mtime":1645960639000},{"fname":"Reverse arrows.md","mtime":1645305706000},{"fname":"Reverse arrows.svg","mtime":1645960639000},{"fname":"Scribble Helper.md","mtime":1682228345043},{"fname":"Scribble Helper.svg","mtime":1645944722000},{"fname":"Select Elements of Type.md","mtime":1643464321000},{"fname":"Select Elements of Type.svg","mtime":1645960639000},{"fname":"Set Dimensions.md","mtime":1645305706000},{"fname":"Set Dimensions.svg","mtime":1645944722000},{"fname":"Set Font Family.md","mtime":1645305706000},{"fname":"Set Font Family.svg","mtime":1645944722000},{"fname":"Set Grid.md","mtime":1674326971324},{"fname":"Set Grid.svg","mtime":1645960639000},{"fname":"Set Link Alias.md","mtime":1645305706000},{"fname":"Set Link Alias.svg","mtime":1645960639000},{"fname":"Set Stroke Width of Selected Elements.md","mtime":1645305706000},{"fname":"Set Stroke Width of Selected Elements.svg","mtime":1645960639000},{"fname":"Set Text Alignment.md","mtime":1645305706000},{"fname":"Set Text Alignment.svg","mtime":1645960639000},{"fname":"Set background color of unclosed line object by adding a shadow clone.md","mtime":1681665030892},{"fname":"Set background color of unclosed line object by adding a shadow clone.svg","mtime":1645960639000},{"fname":"Split text by lines.md","mtime":1645305706000},{"fname":"Split text by lines.svg","mtime":1645944722000},{"fname":"Zoom to Fit Selected Elements.md","mtime":1640770602000},{"fname":"Zoom to Fit Selected Elements.svg","mtime":1645960639000},{"fname":"directory-info.json","mtime":1646583437000},{"fname":"index-new.md","mtime":1645986149000},{"fname":"index.md","mtime":1645175700000},{"fname":"Grid Selected Images.md","mtime":1649614401982},{"fname":"Grid Selected Images.svg","mtime":1649614401982},{"fname":"Palette loader.md","mtime":1686511890942},{"fname":"Palette loader.svg","mtime":1649614401982},{"fname":"Rename Image.md","mtime":1663678478785},{"fname":"Rename Image.svg","mtime":1663678478785},{"fname":"Text Arch.md","mtime":1664095143846},{"fname":"Text Arch.svg","mtime":1670403743278},{"fname":"Deconstruct selected elements into new drawing.md","mtime":1672672112439},{"fname":"Deconstruct selected elements into new drawing.svg","mtime":1668541145255},{"fname":"Slideshow.md","mtime":1685276730052},{"fname":"Slideshow.svg","mtime":1670017348333},{"fname":"Auto Layout.md","mtime":1670403743278},{"fname":"Auto Layout.svg","mtime":1670175947081},{"fname":"Uniform size.md","mtime":1670175947081},{"fname":"Uniform size.svg","mtime":1670175947081},{"fname":"Alternative Pens.md", "mtime":1672942234020},{"fname":"Alternative Pens.svg", "mtime":1672942234020},{"fname":"Mindmap format.md","mtime":1684484694228},{"fname":"Mindmap format.svg","mtime":1674944958059},{"fname":"Text to Sticky Notes.md","mtime":1678537561724},{"fname":"Text to Sticky Notes.svg","mtime":1678537561724},{"fname":"Folder Note Core - Make Current Drawing a Folder.md","mtime":1678973697470},{"fname":"Folder Note Core - Make Current Drawing a Folder.svg","mtime":1678973697470},{"fname":"Invert colors.md","mtime":1678973697470},{"fname":"Invert colors.svg","mtime":1678973697470},{"fname":"Auto Draw for Pen.md","mtime":1680418321236},{"fname":"Auto Draw for Pen.svg","mtime":1680418321236},{"fname":"Hardware Eraser Support.md","mtime":1680418321236},{"fname":"Hardware Eraser Support.svg","mtime":1680418321236},{"fname":"PDF Page Text to Clipboard.md","mtime":1683984041712},{"fname":"PDF Page Text to Clipboard.svg","mtime":1680418321236}] +[{"fname":"Mindmap connector.md","mtime":1658686599427},{"fname":"Mindmap connector.svg","mtime":1658686599427},{"fname":"Add Connector Point.md","mtime":1645305706000},{"fname":"Add Connector Point.svg","mtime":1645944722000},{"fname":"Add Link to Existing File and Open.md","mtime":1647807918345},{"fname":"Add Link to Existing File and Open.svg","mtime":1645964261000},{"fname":"Add Link to New Page and Open.md","mtime":1654168862138},{"fname":"Add Link to New Page and Open.svg","mtime":1645960639000},{"fname":"Add Next Step in Process.md","mtime":1687192028831},{"fname":"Add Next Step in Process.svg","mtime":1645960639000},{"fname":"Box Each Selected Groups.md","mtime":1645305706000},{"fname":"Box Each Selected Groups.svg","mtime":1645967510000},{"fname":"Box Selected Elements.md","mtime":1645305706000},{"fname":"Box Selected Elements.svg","mtime":1645960639000},{"fname":"Change shape of selected elements.md","mtime":1652701169236},{"fname":"Change shape of selected elements.svg","mtime":1645960775000},{"fname":"Connect elements.md","mtime":1645305706000},{"fname":"Connect elements.svg","mtime":1645960639000},{"fname":"Convert freedraw to line.md","mtime":1645305706000},{"fname":"Convert freedraw to line.svg","mtime":1645960639000},{"fname":"Convert selected text elements to sticky notes.md","mtime":1670169501383},{"fname":"Convert selected text elements to sticky notes.svg","mtime":1645960639000},{"fname":"Convert text to link with folder and alias.md","mtime":1641639819000},{"fname":"Convert text to link with folder and alias.svg","mtime":1645960639000},{"fname":"Copy Selected Element Styles to Global.md","mtime":1642232088000},{"fname":"Copy Selected Element Styles to Global.svg","mtime":1645960639000},{"fname":"Create new markdown file and embed into active drawing.md","mtime":1640866935000},{"fname":"Create new markdown file and embed into active drawing.svg","mtime":1645960639000},{"fname":"Darken background color.md","mtime":1663059051059},{"fname":"Darken background color.svg","mtime":1645960639000},{"fname":"Elbow connectors.md","mtime":1671126911490},{"fname":"Elbow connectors.svg","mtime":1645960639000},{"fname":"Expand rectangles horizontally keep text centered.md","mtime":1646563692000},{"fname":"Expand rectangles horizontally keep text centered.svg","mtime":1645967510000},{"fname":"Expand rectangles horizontally.md","mtime":1644950235000},{"fname":"Expand rectangles horizontally.svg","mtime":1645967510000},{"fname":"Expand rectangles vertically keep text centered.md","mtime":1646563692000},{"fname":"Expand rectangles vertically keep text centered.svg","mtime":1645967510000},{"fname":"Expand rectangles vertically.md","mtime":1658686599427},{"fname":"Expand rectangles vertically.svg","mtime":1645967510000},{"fname":"Fixed horizontal distance between centers.md","mtime":1646743234000},{"fname":"Fixed horizontal distance between centers.svg","mtime":1645960639000},{"fname":"Fixed inner distance.md","mtime":1646743234000},{"fname":"Fixed inner distance.svg","mtime":1645960639000},{"fname":"Fixed spacing.md","mtime":1646743234000},{"fname":"Fixed spacing.svg","mtime":1645967510000},{"fname":"Fixed vertical distance between centers.md","mtime":1646743234000},{"fname":"Fixed vertical distance between centers.svg","mtime":1645967510000},{"fname":"Fixed vertical distance.md","mtime":1646743234000},{"fname":"Fixed vertical distance.svg","mtime":1645967510000},{"fname":"Lighten background color.md","mtime":1663059051059},{"fname":"Lighten background color.svg","mtime":1645959546000},{"fname":"Modify background color opacity.md","mtime":1644924415000},{"fname":"Modify background color opacity.svg","mtime":1645944722000},{"fname":"Normalize Selected Arrows.md","mtime":1670403743278},{"fname":"Normalize Selected Arrows.svg","mtime":1645960639000},{"fname":"Organic Line.md","mtime":1672920172531},{"fname":"Organic Line.svg","mtime":1645964261000},{"fname":"README.md","mtime":1645175700000},{"fname":"Repeat Elements.md","mtime":1663059051059},{"fname":"Repeat Elements.svg","mtime":1645960639000},{"fname":"Reverse arrows.md","mtime":1645305706000},{"fname":"Reverse arrows.svg","mtime":1645960639000},{"fname":"Scribble Helper.md","mtime":1682228345043},{"fname":"Scribble Helper.svg","mtime":1645944722000},{"fname":"Select Elements of Type.md","mtime":1643464321000},{"fname":"Select Elements of Type.svg","mtime":1645960639000},{"fname":"Set Dimensions.md","mtime":1645305706000},{"fname":"Set Dimensions.svg","mtime":1645944722000},{"fname":"Set Font Family.md","mtime":1645305706000},{"fname":"Set Font Family.svg","mtime":1645944722000},{"fname":"Set Grid.md","mtime":1674326971324},{"fname":"Set Grid.svg","mtime":1645960639000},{"fname":"Set Link Alias.md","mtime":1645305706000},{"fname":"Set Link Alias.svg","mtime":1645960639000},{"fname":"Set Stroke Width of Selected Elements.md","mtime":1645305706000},{"fname":"Set Stroke Width of Selected Elements.svg","mtime":1645960639000},{"fname":"Set Text Alignment.md","mtime":1645305706000},{"fname":"Set Text Alignment.svg","mtime":1645960639000},{"fname":"Set background color of unclosed line object by adding a shadow clone.md","mtime":1681665030892},{"fname":"Set background color of unclosed line object by adding a shadow clone.svg","mtime":1645960639000},{"fname":"Split text by lines.md","mtime":1645305706000},{"fname":"Split text by lines.svg","mtime":1645944722000},{"fname":"Zoom to Fit Selected Elements.md","mtime":1640770602000},{"fname":"Zoom to Fit Selected Elements.svg","mtime":1645960639000},{"fname":"directory-info.json","mtime":1646583437000},{"fname":"index-new.md","mtime":1645986149000},{"fname":"index.md","mtime":1645175700000},{"fname":"Grid Selected Images.md","mtime":1649614401982},{"fname":"Grid Selected Images.svg","mtime":1649614401982},{"fname":"Palette loader.md","mtime":1686511890942},{"fname":"Palette loader.svg","mtime":1649614401982},{"fname":"Rename Image.md","mtime":1663678478785},{"fname":"Rename Image.svg","mtime":1663678478785},{"fname":"Text Arch.md","mtime":1664095143846},{"fname":"Text Arch.svg","mtime":1670403743278},{"fname":"Deconstruct selected elements into new drawing.md","mtime":1672672112439},{"fname":"Deconstruct selected elements into new drawing.svg","mtime":1668541145255},{"fname":"Slideshow.md","mtime":1685276730052},{"fname":"Slideshow.svg","mtime":1670017348333},{"fname":"Auto Layout.md","mtime":1670403743278},{"fname":"Auto Layout.svg","mtime":1670175947081},{"fname":"Uniform size.md","mtime":1670175947081},{"fname":"Uniform size.svg","mtime":1670175947081},{"fname":"Alternative Pens.md", "mtime":1672942234020},{"fname":"Alternative Pens.svg", "mtime":1672942234020},{"fname":"Mindmap format.md","mtime":1684484694228},{"fname":"Mindmap format.svg","mtime":1674944958059},{"fname":"Text to Sticky Notes.md","mtime":1678537561724},{"fname":"Text to Sticky Notes.svg","mtime":1678537561724},{"fname":"Folder Note Core - Make Current Drawing a Folder.md","mtime":1678973697470},{"fname":"Folder Note Core - Make Current Drawing a Folder.svg","mtime":1678973697470},{"fname":"Invert colors.md","mtime":1678973697470},{"fname":"Invert colors.svg","mtime":1678973697470},{"fname":"Auto Draw for Pen.md","mtime":1680418321236},{"fname":"Auto Draw for Pen.svg","mtime":1680418321236},{"fname":"Hardware Eraser Support.md","mtime":1680418321236},{"fname":"Hardware Eraser Support.svg","mtime":1680418321236},{"fname":"PDF Page Text to Clipboard.md","mtime":1683984041712},{"fname":"PDF Page Text to Clipboard.svg","mtime":1680418321236}] diff --git a/src/ExcalidrawAutomate.ts b/src/ExcalidrawAutomate.ts index 7d55843..ef3659c 100644 --- a/src/ExcalidrawAutomate.ts +++ b/src/ExcalidrawAutomate.ts @@ -612,6 +612,7 @@ export class ExcalidrawAutomate implements ExcalidrawAutomateInterface { y: number, w: number, h: number, + link: string | null = null, ) { return { id, @@ -640,11 +641,33 @@ export class ExcalidrawAutomate implements ExcalidrawAutomateInterface { isDeleted: false, groupIds: [] as any, boundElements: [] as any, - link: null as string, + link, locked: false, }; } + /** + * + * @param topX + * @param topY + * @param width + * @param height + * @returns + */ + addIFrame(topX: number, topY: number, width: number, height: number, url?: string, file?: TFile): string { + const id = nanoid(); + this.elementsDict[id] = this.boxedElement( + id, + "iframe", + topX, + topY, + width, + height, + url ? url : file ? `[[${file.path}]]` : "", + ); + return id; + }; + /** * * @param topX diff --git a/src/ExcalidrawView.ts b/src/ExcalidrawView.ts index 0b535e1..c89dde9 100644 --- a/src/ExcalidrawView.ts +++ b/src/ExcalidrawView.ts @@ -114,6 +114,7 @@ import { setDynamicStyle } from "./utils/DynamicStyling"; import { MenuLinks } from "./menu/MenuLinks"; import { InsertPDFModal } from "./dialogs/InsertPDFModal"; import { CustomIFrame, renderWebView, useDefaultExcalidrawFrame } from "./customIFrame"; +import { insertIFrameToView, insertImageToView } from "./utils/ExcalidrawViewUtils"; declare const PLUGIN_VERSION:string; @@ -2951,6 +2952,7 @@ export default class ExcalidrawView extends TextFileView { case "image": msg = "Embed image";break; case "image-fullsize": msg = "Embed image @100%"; break; case "link": msg = "Insert link"; break; + case "iframe": msg = "Insert in interactive frame"; break; } } else if(e.dataTransfer.types.length === 1 && e.dataTransfer.types.includes("Files")) { //drag from OS file manager @@ -2961,6 +2963,7 @@ export default class ExcalidrawView extends TextFileView { case "image-import": msg = "Import image to Vault"; break; case "image-url": msg = "Insert image/thumbnail with URL"; break; case "insert-link": msg = "Insert link"; break; + case "iframe": msg = "Insert in interactive frame"; break; } } if(this.draginfoDiv.innerText !== msg) this.draginfoDiv.innerText = msg; @@ -3173,6 +3176,7 @@ export default class ExcalidrawView extends TextFileView { const internalDragAction = internalDragModifierType(event); const externalDragAction = externalDragModifierType(event); + //Call Excalidraw Automate onDropHook const onDropHook = ( type: "file" | "text" | "unknown", files: TFile[], @@ -3204,39 +3208,47 @@ export default class ExcalidrawView extends TextFileView { } }; - //Obsidian internal drag event + //--------------------------------------------------------------------------------- + // Obsidian internal drag event + //--------------------------------------------------------------------------------- switch (draggable?.type) { case "file": if (!onDropHook("file", [draggable.file], null)) { + const file:TFile = draggable.file; //https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/422 - if (draggable.file.path.match(REG_LINKINDEX_INVALIDCHARS)) { + if (file.path.match(REG_LINKINDEX_INVALIDCHARS)) { new Notice(t("FILENAME_INVALID_CHARS"), 4000); return false; } if ( ["image", "image-fullsize"].contains(internalDragAction) && - (IMAGE_TYPES.contains(draggable.file.extension) || - draggable.file.extension === "md" || - draggable.file.extension.toLowerCase() === "pdf" ) + (IMAGE_TYPES.contains(file.extension) || + file.extension === "md" || + file.extension.toLowerCase() === "pdf" ) ) { - const ea = getEA(this); - if(draggable.file.extension.toLowerCase() === "pdf") { + if(file.extension.toLowerCase() === "pdf") { const insertPDFModal = new InsertPDFModal(this.plugin, this); - insertPDFModal.open(draggable.file); + insertPDFModal.open(file); } else { - (async () => { - ea.canvas.theme = api.getAppState().theme; - await ea.addImage( - this.currentPosition.x, - this.currentPosition.y, - draggable.file, - !(internalDragAction==="image-fullsize"), - ); - ea.addElementsToView(false, false, true); - })(); + insertImageToView( + getEA(this), + this.currentPosition, + file, + !(internalDragAction==="image-fullsize") + ); } return false; } + + if (internalDragAction === "iframe") { + insertIFrameToView( + getEA(this), + this.currentPosition, + file, + ) + return false; + } + //internalDragAction === "link" this.addText( `[[${app.metadataCache.fileToLinktext( @@ -3272,6 +3284,28 @@ export default class ExcalidrawView extends TextFileView { } return; } + + if (internalDragAction === "iframe") { + const ea = getEA(this) as ExcalidrawAutomate; + let column:number = 0; + let row:number = 0; + for (const f of draggable.files) { + await insertIFrameToView( + ea, + { + x:this.currentPosition.x + column*500, + y:this.currentPosition.y + row*550 + }, + f, + ) + column = (column + 1) % 3; + if(column === 0) { + row++; + } + } + return false; + } + //internalDragAction === "link" for (const f of draggable.files) { await this.addText( @@ -3289,7 +3323,9 @@ export default class ExcalidrawView extends TextFileView { return false; } - //externalDragAction + //--------------------------------------------------------------------------------- + // externalDragAction + //--------------------------------------------------------------------------------- if (event.dataTransfer.types.includes("Files")) { if (event.dataTransfer.types.includes("text/plain")) { const text: string = event.dataTransfer.getData("text"); @@ -3312,6 +3348,15 @@ export default class ExcalidrawView extends TextFileView { return false; } } + if(text && (externalDragAction === "iframe")) { + insertIFrameToView( + getEA(this), + this.currentPosition, + undefined, + text, + ) + return false; + } } if(event.dataTransfer.types.includes("text/html")) { @@ -3333,6 +3378,15 @@ export default class ExcalidrawView extends TextFileView { return false; } } + if(src && (externalDragAction === "iframe")) { + insertIFrameToView( + getEA(this), + this.currentPosition, + undefined, + src[1], + ) + return false; + } } return true; } @@ -3353,6 +3407,9 @@ export default class ExcalidrawView extends TextFileView { return true; } if (!onDropHook("text", null, text)) { + if(text && (externalDragAction==="iframe") && /^(http|https):\/\/[^\s/$.?#].[^\s]*$/.test(text)) { + return true; + } if(text && (externalDragAction==="image-url") && hyperlinkIsYouTubeLink(text)) { this.addYouTubeThumbnail(text); return false; diff --git a/src/customIFrame.tsx b/src/customIFrame.tsx index 25b19de..910f48c 100644 --- a/src/customIFrame.tsx +++ b/src/customIFrame.tsx @@ -185,7 +185,7 @@ function RenderObsidianView( return; } - isActiveRef.current = appState.activeIFrameElement === element; + isActiveRef.current = appState.activeIFrame?.element === element && appState.activeIFrame?.state === "active"; if(!isActiveRef.current) { //@ts-ignore @@ -194,7 +194,7 @@ function RenderObsidianView( app.workspace.setActiveLeaf(view.leaf); return; } - }, [appState.activeIFrameElement, element]); + }, [appState.activeIFrame, element]); return null; }; @@ -220,6 +220,19 @@ export const CustomIFrame: React.FC<{element: NonDeletedExcalidrawElement; radiu view={view} containerRef={containerRef} appState={appState}/> + {(appState.activeIFrame?.element === element && appState.activeIFrame?.state === "hover") && (
)}
) } \ No newline at end of file diff --git a/src/dialogs/UniversalInsertFileModal.ts b/src/dialogs/UniversalInsertFileModal.ts new file mode 100644 index 0000000..0c609ee --- /dev/null +++ b/src/dialogs/UniversalInsertFileModal.ts @@ -0,0 +1,189 @@ +import { ButtonComponent, DropdownComponent, TFile, ToggleComponent } from "obsidian"; +import ExcalidrawView from "../ExcalidrawView"; +import ExcalidrawPlugin from "../main"; +import { Modal, Setting, TextComponent } from "obsidian"; +import { FileSuggestionModal } from "./FolderSuggester"; +import { IMAGE_TYPES, REG_BLOCK_REF_CLEAN } from "src/Constants"; +import { insertIFrameToView, insertImageToView } from "src/utils/ExcalidrawViewUtils"; +import { getEA } from "src"; +import { InsertPDFModal } from "./InsertPDFModal"; +import { ExcalidrawImperativeAPI } from "@zsviczian/excalidraw/types/types"; +import { MAX_IMAGE_SIZE } from "src/Constants"; + +const { + viewportCoordsToSceneCoords + //@ts-ignore +} = excalidrawLib; + +export class UniversalInsertFileModal extends Modal { + private center: { x: number, y: number } = { x: 0, y: 0 }; + constructor( + private plugin: ExcalidrawPlugin, + private view: ExcalidrawView, + ) { + super(app); + const appState = (view.excalidrawAPI as ExcalidrawImperativeAPI).getAppState(); + const containerRect = view.containerEl.getBoundingClientRect(); + const viewportWidth = window.innerWidth || document.documentElement.clientWidth; + const viewportHeight = window.innerHeight || document.documentElement.clientHeight; + + const centerX = containerRect.left + containerRect.width / 2 - MAX_IMAGE_SIZE / 2; + const centerY = containerRect.top + containerRect.height / 2 - MAX_IMAGE_SIZE / 2; + + const clientX = Math.max(0, Math.min(viewportWidth, centerX)); + const clientY = Math.max(0, Math.min(viewportHeight, centerY)); + + this.center = viewportCoordsToSceneCoords ({clientX, clientY}, appState) + } + + onOpen(): void { + this.containerEl.classList.add("excalidraw-release"); + this.titleEl.setText(`Insert File From Vault`); + this.createForm(); + } + + async createForm() { + const ce = this.contentEl; + let sectionPicker: DropdownComponent; + let sectionPickerSetting: Setting; + let actionIFrame: ButtonComponent; + let actionImage: ButtonComponent; + let actionPDF: ButtonComponent; + let sizeToggleSetting: Setting + let anchorTo100: boolean = false; + let file: TFile; + + const updateForm = async () => { + 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 isIFrame = file && !isImage; + const isPDF = file && file.extension === "pdf"; + const isExcalidraw = file && ea.isExcalidrawFile(file); + + if (isMarkdown) { + sectionPickerSetting.settingEl.style.display = ""; + sectionPicker.selectEl.style.display = "block"; + while(sectionPicker.selectEl.options.length > 0) { + sectionPicker.selectEl.remove(0); + } + sectionPicker.addOption("",""); + (await app.metadataCache.blockCache + .getForFile({ isCancelled: () => false },file)) + .blocks.filter((b: any) => b.display && b.node?.type === "heading") + .forEach((b: any) => { + sectionPicker.addOption( + `#${b.display.replaceAll(REG_BLOCK_REF_CLEAN, "").trim()}`, + b.display) + }); + } else { + sectionPickerSetting.settingEl.style.display = "none"; + sectionPicker.selectEl.style.display = "none"; + } + + if (isExcalidraw) { + sizeToggleSetting.settingEl.style.display = ""; + } else { + sizeToggleSetting.settingEl.style.display = "none"; + } + + if (isImage || (file?.extension === "md")) { + actionImage.buttonEl.style.display = "block"; + } else { + actionImage.buttonEl.style.display = "none"; + } + + if (isIFrame) { + actionIFrame.buttonEl.style.display = "block"; + } else { + actionIFrame.buttonEl.style.display = "none"; + } + + if (isPDF) { + actionPDF.buttonEl.style.display = "block"; + } else { + actionPDF.buttonEl.style.display = "none"; + } + + } + + const search = new TextComponent(ce); + search.inputEl.style.width = "100%"; + const suggester = new FileSuggestionModal(this.app, search,app.vault.getFiles().filter((f: TFile) => f!==this.view.file)); + search.onChange(() => { + file = suggester.getSelectedItem(); + updateForm(); + }); + + sectionPickerSetting = new Setting(ce) + .setName("Select section heading") + .addDropdown(dropdown => { + sectionPicker = dropdown; + sectionPicker.selectEl.style.width = "100%"; + }) + + sizeToggleSetting = new Setting(ce) + .setName("Anchor to 100% of original size") + .setDesc("This is a pro feature, use it only if you understand how it works. If enabled even if you change the size of the imported image in Excalidraw, the next time you open the drawing this image will pop back to 100% size. This is useful when embedding an atomic Excalidraw idea into another note and preserving relative sizing of text and icons.") + .addToggle(toggle => { + toggle.setValue(anchorTo100) + .onChange((value) => { + anchorTo100 = value; + }) + }) + + new Setting(ce) + .addButton(button => { + button + .setButtonText("As IFrame") + .setCta() + .onClick(() => { + const path = app.metadataCache.fileToLinktext( + file, + this.view.file.path, + file.extension === "md", + ) + + insertIFrameToView ( + getEA(this.view), + this.center, + //this.view.currentPosition, + undefined, + `[[${path}${sectionPicker.selectEl.value}]]`, + ) + this.close(); + }) + actionIFrame = button; + }) + .addButton(button => { + button + .setButtonText("As PDF") + .setCta() + .onClick(() => { + const insertPDFModal = new InsertPDFModal(this.plugin, this.view); + insertPDFModal.open(file); + this.close(); + }) + actionPDF = button; + }) + .addButton(button => { + button + .setButtonText("As Image") + .setCta() + .onClick(() => { + insertImageToView ( + getEA(this.view), + this.center, + //this.view.currentPosition, + file, + anchorTo100, + ) + this.close(); + }) + actionImage = button; + }) + + search.inputEl.focus(); + updateForm(); + } +} diff --git a/src/lang/locale/en.ts b/src/lang/locale/en.ts index 7c57c95..d4bcc6c 100644 --- a/src/lang/locale/en.ts +++ b/src/lang/locale/en.ts @@ -59,6 +59,7 @@ export default { IMPORT_SVG: "Import an SVG file as Excalidraw strokes (limited SVG support, TEXT currently not supported)", INSERT_MD: "Insert markdown file from vault", INSERT_PDF: "Insert PDF file from vault", + UNIVERSAL_ADD_FILE: "Add a file from the Vault to the drawing", INSERT_LATEX: `Insert LaTeX formula (e.g. \\binom{n}{k} = \\frac{n!}{k!(n-k)!}). ${labelALT()}+CLICK to watch a help video.`, ENTER_LATEX: "Enter a valid LaTeX expression", diff --git a/src/main.ts b/src/main.ts index 0160a1b..3a5a83d 100644 --- a/src/main.ts +++ b/src/main.ts @@ -103,6 +103,7 @@ import Taskbone from "./ocr/Taskbone"; import { emulateCTRLClickForLinks, linkClickModifierType, PaneTarget } from "./utils/ModifierkeyHelper"; import { InsertPDFModal } from "./dialogs/InsertPDFModal"; import { ExportDialog } from "./dialogs/ExportDialog"; +import { UniversalInsertFileModal } from "./dialogs/UniversalInsertFileModal"; declare module "obsidian" { interface App { @@ -1351,6 +1352,23 @@ export default class ExcalidrawPlugin extends Plugin { }, }); + this.addCommand({ + id: "universal-add-file", + name: t("UNIVERSAL_ADD_FILE"), + checkCallback: (checking: boolean) => { + if (checking) { + return Boolean(this.app.workspace.getActiveViewOfType(ExcalidrawView)) + } + const view = this.app.workspace.getActiveViewOfType(ExcalidrawView); + if (view) { + const insertFileModal = new UniversalInsertFileModal(this, view); + insertFileModal.open(); + return true; + } + return false; + }, + }); + this.addCommand({ id: "insert-LaTeX-symbol", name: t("INSERT_LATEX"), diff --git a/src/menu/ActionIcons.tsx b/src/menu/ActionIcons.tsx index a2b4e7a..bcbe0b8 100644 --- a/src/menu/ActionIcons.tsx +++ b/src/menu/ActionIcons.tsx @@ -583,6 +583,22 @@ export const ICONS = { + ), + "add-file": ( + + + + + + ) }; diff --git a/src/menu/ObsidianMenu.tsx b/src/menu/ObsidianMenu.tsx index f7e5af7..bb705fd 100644 --- a/src/menu/ObsidianMenu.tsx +++ b/src/menu/ObsidianMenu.tsx @@ -9,6 +9,7 @@ import { PenStyle } from "src/PenTypes"; import { PENS } from "src/utils/Pens"; import ExcalidrawPlugin from "../main"; import { ICONS, penIcon, stringToSVG } from "./ActionIcons"; +import { UniversalInsertFileModal } from "src/dialogs/UniversalInsertFileModal"; declare const PLUGIN_VERSION:string; @@ -254,6 +255,23 @@ export class ObsidianMenu { {ICONS.obsidian} + {this.renderCustomPens(isMobile,appState)} {this.renderPinnedScriptButtons(isMobile,appState)} diff --git a/src/utils/ExcalidrawViewUtils.ts b/src/utils/ExcalidrawViewUtils.ts new file mode 100644 index 0000000..e183ccf --- /dev/null +++ b/src/utils/ExcalidrawViewUtils.ts @@ -0,0 +1,45 @@ + +import { MAX_IMAGE_SIZE } from "src/Constants"; +import { TFile } from "obsidian"; +import { IMAGE_TYPES } from "src/Constants"; +import { ExcalidrawAutomate } from "src/ExcalidrawAutomate"; + +export const insertImageToView = async ( + ea: ExcalidrawAutomate, + position: { x: number, y: number }, + file: TFile, + scale?: boolean, +) => { + ea.clear(); + const api = ea.getExcalidrawAPI(); + ea.canvas.theme = api.getAppState().theme; + await ea.addImage( + position.x, + position.y, + file, + scale, + ); + ea.addElementsToView(false, false, true); +} + +export const insertIFrameToView = async ( + ea: ExcalidrawAutomate, + position: { x: number, y: number }, + file?: TFile, + link?: string, +) => { + ea.clear(); + if(file && IMAGE_TYPES.contains(file.extension) || ea.isExcalidrawFile(file)) { + await insertImageToView(ea, position, file); + } else { + ea.addIFrame( + position.x, + position.y, + MAX_IMAGE_SIZE, + MAX_IMAGE_SIZE, + link, + file, + ); + ea.addElementsToView(false, false, true); + } +} \ No newline at end of file diff --git a/src/utils/ModifierkeyHelper.ts b/src/utils/ModifierkeyHelper.ts index 2b7f9de..603215b 100644 --- a/src/utils/ModifierkeyHelper.ts +++ b/src/utils/ModifierkeyHelper.ts @@ -2,8 +2,8 @@ import { DEVICE, isDarwin } from "src/Constants"; 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"; -export type InternalDragAction = "link"|"image"|"image-fullsize"; +export type ExternalDragAction = "insert-link"|"image-url"|"image-import"|"iframe"; +export type InternalDragAction = "link"|"image"|"image-fullsize"|"iframe"; export const labelCTRL = () => DEVICE.isIOS || DEVICE.isMacOS ? "CMD" : "CTRL"; export const labelALT = () => DEVICE.isIOS || DEVICE.isMacOS ? "OPT" : "ALT"; @@ -31,6 +31,7 @@ export const linkClickModifierType = (ev: KeyEvent):PaneTarget => { } export const externalDragModifierType = (ev: KeyEvent):ExternalDragAction => { + if( isSHIFT(ev) && isCTRL(ev) && !isALT(ev) && !isMETA(ev)) return "iframe"; if(!isSHIFT(ev) && isCTRL(ev) && !isALT(ev) && !isMETA(ev)) return "insert-link"; if(!isSHIFT(ev) && !isCTRL(ev) && !isALT(ev) && isMETA(ev)) return "insert-link"; if( isSHIFT(ev) && !isCTRL(ev) && !isALT(ev) && !isMETA(ev)) return "image-import"; @@ -40,6 +41,7 @@ export const externalDragModifierType = (ev: KeyEvent):ExternalDragAction => { //https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/468 export const internalDragModifierType = (ev: KeyEvent):InternalDragAction => { + if( isSHIFT(ev) && isCTRL(ev) && !isALT(ev) && !isMETA(ev)) return "iframe"; 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";