1
1
import { htmlEscape } from 'escape-goat' ;
2
2
import { POST } from '../../modules/fetch.js' ;
3
3
import { imageInfo } from '../../utils/image.js' ;
4
- import { replaceTextareaSelection } from '../../utils/dom.js' ;
4
+ import { createElementFromAttrs , replaceTextareaSelection } from '../../utils/dom.js' ;
5
5
import { isUrl } from '../../utils/url.js' ;
6
- import { extname } from '../../utils.js' ;
6
+ import { extname , isWellKnownImageFilename } from '../../utils.js' ;
7
7
import { triggerEditorContentChanged } from './EditorMarkdown.js' ;
8
- import { getComboMarkdownEditor } from './ComboMarkdownEditor.js' ;
9
8
10
9
async function uploadFile ( file , uploadUrl ) {
11
10
const formData = new FormData ( ) ;
@@ -81,43 +80,51 @@ class CodeMirrorEditor {
81
80
}
82
81
}
83
82
84
- // FIXME: handle non-image files
85
- async function handleClipboardImages ( editor , dropzone , images , e ) {
83
+ function isImageFile ( file ) {
84
+ return file . type ?. startsWith ( 'image/' ) || isWellKnownImageFilename ( file . name ) ;
85
+ }
86
+
87
+ async function handleUploadFiles ( editor , dropzone , files , e ) {
86
88
const uploadUrl = dropzone . getAttribute ( 'data-upload-url' ) ;
87
89
const filesContainer = dropzone . querySelector ( '.files' ) ;
88
90
89
91
e . preventDefault ( ) ;
90
92
e . stopPropagation ( ) ;
91
93
92
- for ( const img of images ) {
93
- const name = img . name . slice ( 0 , img . name . lastIndexOf ( '.' ) ) ;
94
- const { width, dppx} = await imageInfo ( img ) ;
95
- const placeholder = `` ;
94
+ for ( const file of files ) {
95
+ const name = file . name . slice ( 0 , file . name . lastIndexOf ( '.' ) ) ;
96
+ const isImage = isImageFile ( file ) ;
97
+
98
+ let placeholder = `[${ name } ](uploading ...)` ;
99
+ if ( isImage ) placeholder = `!${ placeholder } ` ;
96
100
97
101
editor . insertPlaceholder ( placeholder ) ;
98
- const { uuid} = await uploadFile ( img , uploadUrl ) ;
99
-
100
- let text ;
101
- if ( width > 0 && dppx > 1 ) {
102
- // Scale down images from HiDPI monitors. This uses the <img> tag because it's the only
103
- // method to change image size in Markdown that is supported by all implementations.
104
- // Make the image link relative to the repo path, then the final URL is "/sub-path/owner/repo/attachments/{uuid}"
105
- const url = `attachments/${ uuid } ` ;
106
- text = `<img width="${ Math . round ( width / dppx ) } " alt="${ htmlEscape ( name ) } " src="${ htmlEscape ( url ) } ">` ;
102
+ const { uuid} = await uploadFile ( file , uploadUrl ) ;
103
+
104
+ let fileMarkdownLink ;
105
+ if ( isImage ) {
106
+ const { width, dppx} = await imageInfo ( file ) ;
107
+ if ( width > 0 && dppx > 1 ) {
108
+ // Scale down images from HiDPI monitors. This uses the <img> tag because it's the only
109
+ // method to change image size in Markdown that is supported by all implementations.
110
+ // Make the image link relative to the repo path, then the final URL is "/sub-path/owner/repo/attachments/{uuid}"
111
+ const url = `attachments/${ uuid } ` ;
112
+ fileMarkdownLink = `<img width="${ Math . round ( width / dppx ) } " alt="${ htmlEscape ( name ) } " src="${ htmlEscape ( url ) } ">` ;
113
+ } else {
114
+ // Markdown always renders the image with a relative path, so the final URL is "/sub-path/owner/repo/attachments/{uuid}"
115
+ // TODO: it should also use relative path for consistency, because absolute is ambiguous for "/sub-path/attachments" or "/attachments"
116
+ const url = `/attachments/${ uuid } ` ;
117
+ fileMarkdownLink = `` ;
118
+ }
107
119
} else {
108
- // Markdown always renders the image with a relative path, so the final URL is "/sub-path/owner/repo/attachments/{uuid}"
109
- // TODO: it should also use relative path for consistency, because absolute is ambiguous for "/sub-path/attachments" or "/attachments"
110
120
const url = `/attachments/${ uuid } ` ;
111
- text = `! [${ name } ](${ url } )` ;
121
+ fileMarkdownLink = `[${ name } ](${ url } )` ;
112
122
}
113
- editor . replacePlaceholder ( placeholder , text ) ;
123
+ editor . replacePlaceholder ( placeholder , fileMarkdownLink ) ;
114
124
115
- const input = document . createElement ( 'input' ) ;
116
- input . setAttribute ( 'name' , 'files' ) ;
117
- input . setAttribute ( 'type' , 'hidden' ) ;
118
- input . setAttribute ( 'id' , uuid ) ;
119
- input . value = uuid ;
125
+ const input = createElementFromAttrs ( 'input' , { type : 'hidden' , name : 'files' , id : `dropzone-file-${ uuid } ` , value : uuid } ) ;
120
126
filesContainer . append ( input ) ;
127
+ // TODO: add upload preview item
121
128
}
122
129
}
123
130
@@ -152,7 +159,7 @@ export function initEasyMDEPaste(easyMDE, dropzone) {
152
159
easyMDE . codemirror . on ( 'paste' , ( _ , e ) => {
153
160
const { images} = getPastedContent ( e ) ;
154
161
if ( images . length ) {
155
- handleClipboardImages ( new CodeMirrorEditor ( easyMDE . codemirror ) , dropzone , images , e ) ;
162
+ handleUploadFiles ( new CodeMirrorEditor ( easyMDE . codemirror ) , dropzone , images , e ) ;
156
163
}
157
164
} ) ;
158
165
}
@@ -168,22 +175,22 @@ export function initTextareaPaste(textarea, dropzone) {
168
175
textarea . addEventListener ( 'paste' , ( e ) => {
169
176
const { images, text} = getPastedContent ( e ) ;
170
177
if ( images . length ) {
171
- handleClipboardImages ( new TextareaEditor ( textarea ) , dropzone , images , e ) ;
178
+ handleUploadFiles ( new TextareaEditor ( textarea ) , dropzone , images , e ) ;
172
179
} else if ( text ) {
173
180
handleClipboardText ( textarea , e , { text, isShiftDown} ) ;
174
181
}
175
182
} ) ;
176
183
textarea . addEventListener ( 'drop' , ( e ) => {
177
- const acceptedFiles = getComboMarkdownEditor ( textarea ) . dropzone . getAttribute ( 'data-accepts' ) ;
184
+ const acceptedFiles = dropzone . getAttribute ( 'data-accepts' ) ;
178
185
const files = [ ] ;
179
- for ( const item of e . dataTransfer ? .items ?? [ ] ) {
186
+ for ( const item of e . dataTransfer . items ) {
180
187
if ( item ?. kind !== 'file' ) continue ;
181
188
const file = item . getAsFile ( ) ;
189
+ // FIXME: the check is not right. acceptedFiles could be ".zip, audio/*, image/png, */*"
182
190
if ( acceptedFiles . includes ( extname ( file . name ) ) ) {
183
191
files . push ( file ) ;
184
192
}
185
193
}
186
- // FIXME: handle upload files
187
- handleClipboardImages ( new TextareaEditor ( textarea ) , dropzone , files , e ) ;
194
+ handleUploadFiles ( new TextareaEditor ( textarea ) , dropzone , files , e ) ;
188
195
} ) ;
189
196
}
0 commit comments