Skip to content

Commit 381e84e

Browse files
author
Amelia Wattenberger
authored
Merge pull request #73 from githubnext/aw/image-paste
Add ability to paste image to Markdown block
2 parents 71e08a6 + b627255 commit 381e84e

File tree

3 files changed

+59
-13
lines changed

3 files changed

+59
-13
lines changed

blocks/file-blocks/markdown-edit/copy-widget.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -559,10 +559,8 @@ export const parseImageUrl = (
559559
url: string,
560560
context: FileContext | FolderContext
561561
) => {
562-
if (!url.startsWith("http")) {
563-
const pathRoot = context.path.split("/").slice(0, -1).join("/");
564-
return `https://raw.githubusercontent.com/${context.owner}/${context.repo}/${context.sha}/${pathRoot}/${url}`;
565-
} else {
566-
return url;
567-
}
562+
if (url.startsWith("http")) return url;
563+
if (url.startsWith("data:")) return url;
564+
const pathRoot = context.path.split("/").slice(0, -1).join("/");
565+
return `https://raw.githubusercontent.com/${context.owner}/${context.repo}/${context.sha}/${pathRoot}/${url}`;
568566
};

blocks/file-blocks/markdown-edit/extensions.ts

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import {
3232
import { tags } from "@lezer/highlight";
3333
import interact from "@replit/codemirror-interact";
3434
import { blockComponentWidget } from "./block-component-widget";
35-
import { copy, markdownKeymap } from "./copy-widget";
35+
import { copy, markdownKeymap, pasteKeymap } from "./copy-widget";
3636
import { images } from "./image-widget";
3737
import "./style.css";
3838
import { theme } from "./theme";
@@ -96,6 +96,7 @@ export function makeExtensions({
9696
},
9797
},
9898
]),
99+
99100
EditorView.updateListener.of((v) => {
100101
if (!v.docChanged) return;
101102
onUpdateContent(v.state.doc.sliceString(0));
@@ -108,6 +109,7 @@ export function makeExtensions({
108109
const text = v.state.doc.sliceString(0, cursorPosition);
109110
const activeLine = text.split("\n").slice(-1)[0];
110111
const startOfLinePosition = cursorPosition - activeLine.length;
112+
111113
const isAutocompleting =
112114
activeLine.startsWith("/") && !activeLine.includes("/>");
113115
if (!isAutocompleting) {
@@ -124,6 +126,54 @@ export function makeExtensions({
124126
}
125127
}),
126128

129+
EditorView.domEventHandlers({
130+
paste(e, view) {
131+
const value = e.clipboardData?.items[0];
132+
const MAX_URL_SIZE = 5000000;
133+
// handle images pasted from the web
134+
if (value && value.type === "text/html") {
135+
value.getAsString((str) => {
136+
const htmlImgRegex = /<img[^>]*src="(?<src>[^"]*)"[^>]*>/gim;
137+
const matches = [...str.matchAll(htmlImgRegex)];
138+
const images = matches.map((match) => match.groups?.src);
139+
if (images) {
140+
view.dispatch({
141+
changes: {
142+
from: view.state.selection.main.from,
143+
to: view.state.selection.main.to,
144+
insert: images
145+
.filter((image) => image && image.length < MAX_URL_SIZE)
146+
.map((image) => `![${image}](${image})`)
147+
.join("\n"),
148+
},
149+
});
150+
}
151+
});
152+
} else if (
153+
value &&
154+
["image/png", "image/jpeg"].includes(value.type || "")
155+
) {
156+
const file = value.getAsFile();
157+
if (file) {
158+
const reader = new FileReader();
159+
reader.onload = (e) => {
160+
const image = e.target?.result as string;
161+
if (image && image.length < MAX_URL_SIZE) {
162+
view.dispatch({
163+
changes: {
164+
from: view.state.selection.main.from,
165+
to: view.state.selection.main.to,
166+
insert: `![${file.name}](${image})`,
167+
},
168+
});
169+
}
170+
};
171+
reader.readAsDataURL(file);
172+
}
173+
}
174+
},
175+
}),
176+
127177
// lineNumbers(),
128178
highlightActiveLineGutter(),
129179
highlightSpecialChars(),

blocks/file-blocks/markdown-edit/image-widget.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -156,10 +156,8 @@ export const parseImageUrl = (
156156
url: string,
157157
context: FileContext | FolderContext
158158
) => {
159-
if (!url.startsWith("http")) {
160-
const pathRoot = context.path.split("/").slice(0, -1).join("/");
161-
return `https://raw.githubusercontent.com/${context.owner}/${context.repo}/${context.sha}/${pathRoot}/${url}`;
162-
} else {
163-
return url;
164-
}
159+
if (url.startsWith("http")) return url;
160+
if (url.startsWith("data:")) return url;
161+
const pathRoot = context.path.split("/").slice(0, -1).join("/");
162+
return `https://raw.githubusercontent.com/${context.owner}/${context.repo}/${context.sha}/${pathRoot}/${url}`;
165163
};

0 commit comments

Comments
 (0)