@@ -32,7 +32,7 @@ import {
32
32
import { tags } from "@lezer/highlight" ;
33
33
import interact from "@replit/codemirror-interact" ;
34
34
import { blockComponentWidget } from "./block-component-widget" ;
35
- import { copy , markdownKeymap } from "./copy-widget" ;
35
+ import { copy , markdownKeymap , pasteKeymap } from "./copy-widget" ;
36
36
import { images } from "./image-widget" ;
37
37
import "./style.css" ;
38
38
import { theme } from "./theme" ;
@@ -96,6 +96,7 @@ export function makeExtensions({
96
96
} ,
97
97
} ,
98
98
] ) ,
99
+
99
100
EditorView . updateListener . of ( ( v ) => {
100
101
if ( ! v . docChanged ) return ;
101
102
onUpdateContent ( v . state . doc . sliceString ( 0 ) ) ;
@@ -108,6 +109,7 @@ export function makeExtensions({
108
109
const text = v . state . doc . sliceString ( 0 , cursorPosition ) ;
109
110
const activeLine = text . split ( "\n" ) . slice ( - 1 ) [ 0 ] ;
110
111
const startOfLinePosition = cursorPosition - activeLine . length ;
112
+
111
113
const isAutocompleting =
112
114
activeLine . startsWith ( "/" ) && ! activeLine . includes ( "/>" ) ;
113
115
if ( ! isAutocompleting ) {
@@ -124,6 +126,54 @@ export function makeExtensions({
124
126
}
125
127
} ) ,
126
128
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 = / < i m g [ ^ > ] * s r c = " (?< 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 ) => `` )
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 : `` ,
167
+ } ,
168
+ } ) ;
169
+ }
170
+ } ;
171
+ reader . readAsDataURL ( file ) ;
172
+ }
173
+ }
174
+ } ,
175
+ } ) ,
176
+
127
177
// lineNumbers(),
128
178
highlightActiveLineGutter ( ) ,
129
179
highlightSpecialChars ( ) ,
0 commit comments