@@ -7,6 +7,7 @@ import {ExtensionAuto} from '../../../../core';
77import { isFunction } from '../../../../lodash' ;
88import { FileUploadHandler } from '../../../../utils/upload' ;
99import { clipboardUtils } from '../../../behavior/Clipboard' ;
10+ import { DataTransferType } from '../../../behavior/Clipboard/utils' ;
1011import { ImageAttr , ImgSizeAttr , imageType } from '../../../specs' ;
1112import { CreateImageNodeOptions , isImageNode } from '../utils' ;
1213
@@ -15,12 +16,22 @@ import {ImagesUploadProcess} from './upload';
1516const { isFilesFromHtml, isFilesOnly, isImageFile} = clipboardUtils ;
1617
1718export type ImagePasteOptions = Pick < CreateImageNodeOptions , 'needDimmensions' > & {
18- imageUploadHandler : FileUploadHandler ;
19+ imageUploadHandler ?: FileUploadHandler ;
20+ /**
21+ * The function, used to determine if the pasted text is the image url and should be inserted as an image
22+ */
23+ parseInsertedUrlAsImage ?: ( text : string ) => { imageUrl : string ; title ?: string } | null ;
1924} ;
2025
2126export const ImagePaste : ExtensionAuto < ImagePasteOptions > = ( builder , opts ) => {
22- if ( ! opts || ! isFunction ( opts . imageUploadHandler ) )
23- throw new Error ( 'ImagePaste extension: imageUploadHandler is not a function' ) ;
27+ const { parseInsertedUrlAsImage, imageUploadHandler} = opts ?? { } ;
28+
29+ if ( ! isFunction ( imageUploadHandler ?? parseInsertedUrlAsImage ) )
30+ throw new Error (
31+ `ImagePaste extension: ${
32+ opts . imageUploadHandler ? 'imageUploadHandler' : 'parseInsertedUrlAsImage'
33+ } is not a function`,
34+ ) ;
2435
2536 builder . addPlugin (
2637 ( ) =>
@@ -29,20 +40,46 @@ export const ImagePaste: ExtensionAuto<ImagePasteOptions> = (builder, opts) => {
2940 handleDOMEvents : {
3041 paste ( view , e ) {
3142 const files = getPastedImages ( e . clipboardData ) ;
32- if ( files ) {
43+ if ( imageUploadHandler && files ) {
3344 e . preventDefault ( ) ;
3445 new ImagesUploadProcess (
3546 view ,
3647 files ,
37- opts . imageUploadHandler ,
48+ imageUploadHandler ,
3849 view . state . tr . selection . from ,
3950 opts ,
4051 ) . run ( ) ;
52+ return true ;
53+ } else if ( parseInsertedUrlAsImage ) {
54+ const { imageUrl, title} =
55+ parseInsertedUrlAsImage (
56+ e . clipboardData ?. getData ( DataTransferType . Text ) ?? '' ,
57+ ) || { } ;
58+
59+ if ( ! imageUrl ) {
60+ return false ;
61+ }
62+
63+ e . preventDefault ( ) ;
64+
65+ const imageNode = imageType ( view . state . schema ) . create ( {
66+ src : imageUrl ,
67+ alt : title ,
68+ } ) ;
69+
70+ const tr = view . state . tr . replaceSelectionWith ( imageNode ) ;
71+ view . dispatch ( tr . scrollIntoView ( ) ) ;
72+
4173 return true ;
4274 }
75+
4376 return false ;
4477 } ,
4578 drop ( view , e ) {
79+ if ( ! imageUploadHandler ) {
80+ return false ;
81+ }
82+
4683 // handle drop images from device
4784 if ( view . dragging ) return false ;
4885
@@ -63,7 +100,7 @@ export const ImagePaste: ExtensionAuto<ImagePasteOptions> = (builder, opts) => {
63100 new ImagesUploadProcess (
64101 view ,
65102 files ,
66- opts . imageUploadHandler ,
103+ imageUploadHandler ,
67104 posToInsert ,
68105 opts ,
69106 ) . run ( ) ;
@@ -74,6 +111,10 @@ export const ImagePaste: ExtensionAuto<ImagePasteOptions> = (builder, opts) => {
74111 } ,
75112 } ,
76113 handlePaste ( view , _event , slice ) {
114+ if ( ! imageUploadHandler ) {
115+ return false ;
116+ }
117+
77118 const node = sliceSingleNode ( slice ) ;
78119 if ( node && isImageNode ( node ) ) {
79120 const imgUrl = node . attrs [ ImgSizeAttr . Src ] ;
@@ -82,7 +123,7 @@ export const ImagePaste: ExtensionAuto<ImagePasteOptions> = (builder, opts) => {
82123 new ImagesUploadProcess (
83124 view ,
84125 [ imgFile ] ,
85- opts . imageUploadHandler ,
126+ imageUploadHandler ,
86127 view . state . tr . selection . from ,
87128 opts ,
88129 ) . run ( ) ;
0 commit comments