|
|
|
@ -11,14 +11,14 @@ const DRAGOVER_CLASS_LIST = [ |
|
|
|
'rounded-md' |
|
|
|
'rounded-md' |
|
|
|
] |
|
|
|
] |
|
|
|
|
|
|
|
|
|
|
|
export interface FileHandlerOptions { |
|
|
|
export interface ClipboardAndDropHandlerOptions { |
|
|
|
onUploadStart?: (file: File) => void |
|
|
|
onUploadStart?: (file: File) => void |
|
|
|
onUploadSuccess?: (file: File, result: any) => void |
|
|
|
onUploadSuccess?: (file: File, result: any) => void |
|
|
|
onUploadError?: (file: File, error: any) => void |
|
|
|
onUploadError?: (file: File, error: any) => void |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
export const FileHandler = Extension.create<FileHandlerOptions>({ |
|
|
|
export const ClipboardAndDropHandler = Extension.create<ClipboardAndDropHandlerOptions>({ |
|
|
|
name: 'fileHandler', |
|
|
|
name: 'clipboardAndDropHandler', |
|
|
|
|
|
|
|
|
|
|
|
addOptions() { |
|
|
|
addOptions() { |
|
|
|
return { |
|
|
|
return { |
|
|
|
@ -61,17 +61,38 @@ export const FileHandler = Extension.create<FileHandlerOptions>({ |
|
|
|
}, |
|
|
|
}, |
|
|
|
handlePaste(view, event) { |
|
|
|
handlePaste(view, event) { |
|
|
|
const items = Array.from(event.clipboardData?.items ?? []) |
|
|
|
const items = Array.from(event.clipboardData?.items ?? []) |
|
|
|
const mediaItem = items.find( |
|
|
|
let handled = false |
|
|
|
(item) => item.type.includes('image') || item.type.includes('video') |
|
|
|
|
|
|
|
) |
|
|
|
for (const item of items) { |
|
|
|
if (!mediaItem) return false |
|
|
|
if ( |
|
|
|
|
|
|
|
item.kind === 'file' && |
|
|
|
const file = mediaItem.getAsFile() |
|
|
|
(item.type.includes('image') || item.type.includes('video')) |
|
|
|
if (!file) return false |
|
|
|
) { |
|
|
|
|
|
|
|
const file = item.getAsFile() |
|
|
|
|
|
|
|
if (file) { |
|
|
|
uploadFile(view, file, options) |
|
|
|
uploadFile(view, file, options) |
|
|
|
|
|
|
|
handled = true |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else if (item.kind === 'string' && item.type === 'text/plain') { |
|
|
|
|
|
|
|
item.getAsString((text) => { |
|
|
|
|
|
|
|
const { schema } = view.state |
|
|
|
|
|
|
|
const parts = text.split('\n') |
|
|
|
|
|
|
|
const nodes = [] |
|
|
|
|
|
|
|
for (let i = 0; i < parts.length; i++) { |
|
|
|
|
|
|
|
if (i > 0) nodes.push(schema.nodes.hardBreak.create()) |
|
|
|
|
|
|
|
if (parts[i]) nodes.push(schema.text(parts[i])) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
const fragment = schema.nodes.paragraph.create(null, nodes) |
|
|
|
|
|
|
|
const tr = view.state.tr.replaceSelectionWith(fragment) |
|
|
|
|
|
|
|
view.dispatch(tr) |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
handled = true |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return true |
|
|
|
// Only handle the first file/string item
|
|
|
|
|
|
|
|
if (handled) break |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return handled |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
}) |
|
|
|
}) |
|
|
|
@ -79,7 +100,7 @@ export const FileHandler = Extension.create<FileHandlerOptions>({ |
|
|
|
} |
|
|
|
} |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
async function uploadFile(view: EditorView, file: File, options: FileHandlerOptions) { |
|
|
|
async function uploadFile(view: EditorView, file: File, options: ClipboardAndDropHandlerOptions) { |
|
|
|
const name = file.name |
|
|
|
const name = file.name |
|
|
|
|
|
|
|
|
|
|
|
options.onUploadStart?.(file) |
|
|
|
options.onUploadStart?.(file) |