mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-08 17:02:17 +00:00
feat(editor): paste and drop images into Markdown files (#489)
Pasting or dropping an image into a Markdown editor saves it beside the document in `assets/` and inserts a URL-encoded relative link as one undo step, in local and remote projects. Existing names get numbered suffixes; the folder and clipboard name pattern are in Settings › Editor › General. Non-Markdown editors, text paste and other dropped files keep their behavior. Fixes #308
This commit is contained in:
1 parent
f592ff5b05
commit
df6ed5ccba
18 files changed
+498
-2
No files matched your search
@@ -2,7 +2,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { useProject } from "@/platform/project";
|
||||
import { useRemote } from "@/platform/remote";
|
||||
import type { RemoteSession } from "@/platform/ipc";
|
||||
import { handleFileDrop, type FileDropDeps } from "./fileDrop";
|
||||
import { handleFileDrop, registerFileDropHandler, type FileDropDeps } from "./fileDrop";
|
||||
|
||||
function deps(dirs: string[] = []) {
|
||||
const calls: string[] = [];
|
||||
@@ -38,6 +38,20 @@ describe("files dropped from the OS", () => {
|
||||
document.body.innerHTML = "";
|
||||
});
|
||||
|
||||
it("lets an editor consume image drops before opening files, including remote windows", async () => {
|
||||
useRemote.setState({ session: { id: "remote" } as unknown as RemoteSession });
|
||||
const { d, calls } = deps();
|
||||
const handler = vi.fn(() => true);
|
||||
const unregister = registerFileDropHandler(handler);
|
||||
try {
|
||||
await handleFileDrop(["/local/image.png"], 1, 1, d);
|
||||
expect(handler).toHaveBeenCalledWith(["/local/image.png"], 1, 1);
|
||||
expect(calls).toEqual([]);
|
||||
} finally {
|
||||
unregister();
|
||||
}
|
||||
});
|
||||
|
||||
it("opens each dropped file in its own tab, focusing the last; works for files outside the project", async () => {
|
||||
const { d, calls } = deps();
|
||||
await handleFileDrop(["/p/a.ts", "/elsewhere/notes.md"], 1, 1, d);
|
||||
|
||||
@@ -12,6 +12,16 @@ import { editorService, OWNS_FILE_DROP } from "./contributions";
|
||||
|
||||
const OWNER_ATTR = Object.keys(OWNS_FILE_DROP)[0]!;
|
||||
|
||||
type FileDropHandler = (paths: readonly string[], x: number, y: number) => boolean;
|
||||
const fileDropHandlers = new Set<FileDropHandler>();
|
||||
|
||||
export function registerFileDropHandler(handler: FileDropHandler): () => void {
|
||||
fileDropHandlers.add(handler);
|
||||
return () => {
|
||||
fileDropHandlers.delete(handler);
|
||||
};
|
||||
}
|
||||
|
||||
export interface FileDropDeps {
|
||||
isDir(path: string): Promise<boolean>;
|
||||
openFile(path: string, focus: boolean): Promise<void>;
|
||||
@@ -46,6 +56,7 @@ export function handleFileDrop(
|
||||
y: number,
|
||||
deps: FileDropDeps = defaultDeps,
|
||||
): Promise<void> | null {
|
||||
for (const handler of fileDropHandlers) if (paths.length && handler(paths, x, y)) return Promise.resolve();
|
||||
const { project, lightEdit } = useProject.getState();
|
||||
if (!paths.length || !(project || lightEdit) || isRemoteWindow() || dropOwnedAt(x, y)) return null;
|
||||
return openDropped(paths, deps);
|
||||
|
||||
Reference in new issue
Block a user