11import { htmlEscape } from 'escape-goat' ;
22import { POST } from '../../modules/fetch.js' ;
33import { imageInfo } from '../../utils/image.js' ;
4+ import { getPastedContent , replaceTextareaSelection } from '../../utils/dom.js' ;
5+ import { isUrl } from '../../utils/url.js' ;
46
57async function uploadFile ( file , uploadUrl ) {
68 const formData = new FormData ( ) ;
@@ -10,17 +12,6 @@ async function uploadFile(file, uploadUrl) {
1012 return await res . json ( ) ;
1113}
1214
13- function clipboardPastedImages ( e ) {
14- if ( ! e . clipboardData ) return [ ] ;
15-
16- const files = [ ] ;
17- for ( const item of e . clipboardData . items || [ ] ) {
18- if ( ! item . type || ! item . type . startsWith ( 'image/' ) ) continue ;
19- files . push ( item . getAsFile ( ) ) ;
20- }
21- return files ;
22- }
23-
2415function triggerEditorContentChanged ( target ) {
2516 target . dispatchEvent ( new CustomEvent ( 'ce-editor-content-changed' , { bubbles : true } ) ) ;
2617}
@@ -91,20 +82,16 @@ class CodeMirrorEditor {
9182 }
9283}
9384
94- const uploadClipboardImage = async ( editor , dropzone , e ) => {
85+ async function handleClipboardImages ( editor , dropzone , images , e ) {
9586 const uploadUrl = dropzone . getAttribute ( 'data-upload-url' ) ;
9687 const filesContainer = dropzone . querySelector ( '.files' ) ;
9788
98- if ( ! uploadUrl || ! filesContainer ) return ;
89+ if ( ! dropzone || ! uploadUrl || ! filesContainer || ! images . length ) return ;
9990
100- const pastedImages = clipboardPastedImages ( e ) ;
101- if ( ! pastedImages || pastedImages . length === 0 ) {
102- return ;
103- }
10491 e . preventDefault ( ) ;
10592 e . stopPropagation ( ) ;
10693
107- for ( const img of pastedImages ) {
94+ for ( const img of images ) {
10895 const name = img . name . slice ( 0 , img . name . lastIndexOf ( '.' ) ) ;
10996
11097 const placeholder = `` ;
@@ -131,18 +118,37 @@ const uploadClipboardImage = async (editor, dropzone, e) => {
131118 input . value = uuid ;
132119 filesContainer . append ( input ) ;
133120 }
134- } ;
121+ }
122+
123+ function handleClipboardText ( textarea , text , e ) {
124+ // when pasting links over selected text, turn it into [text](link)
125+ const { value, selectionStart, selectionEnd} = textarea ;
126+ const selectedText = value . substring ( selectionStart , selectionEnd ) ;
127+ const trimmedText = text . trim ( ) ;
128+ if ( selectedText && isUrl ( trimmedText ) ) {
129+ e . stopPropagation ( ) ;
130+ e . preventDefault ( ) ;
131+ replaceTextareaSelection ( textarea , `[${ selectedText } ](${ trimmedText } )` ) ;
132+ }
133+ }
135134
136135export function initEasyMDEImagePaste ( easyMDE , dropzone ) {
137- if ( ! dropzone ) return ;
138- easyMDE . codemirror . on ( 'paste' , async ( _ , e ) => {
139- return uploadClipboardImage ( new CodeMirrorEditor ( easyMDE . codemirror ) , dropzone , e ) ;
136+ easyMDE . codemirror . on ( 'paste' , ( _ , e ) => {
137+ const { images} = getPastedContent ( e ) ;
138+ if ( images . length ) {
139+ handleClipboardImages ( new CodeMirrorEditor ( easyMDE . codemirror ) , dropzone , images , e ) ;
140+ }
140141 } ) ;
141142}
142143
143144export function initTextareaImagePaste ( textarea , dropzone ) {
144- if ( ! dropzone ) return ;
145- textarea . addEventListener ( 'paste' , async ( e ) => {
146- return uploadClipboardImage ( new TextareaEditor ( textarea ) , dropzone , e ) ;
145+ textarea . addEventListener ( 'paste' , ( e ) => {
146+ const { images, text} = getPastedContent ( e ) ;
147+ if ( text ) {
148+ handleClipboardText ( textarea , text , e ) ;
149+ }
150+ if ( images . length ) {
151+ handleClipboardImages ( new TextareaEditor ( textarea ) , dropzone , images , e ) ;
152+ }
147153 } ) ;
148154}
0 commit comments