fix: Cannot upload multiple files at once from editor command menu (#4957)
This commit is contained in:
@@ -290,7 +290,7 @@ class CommandMenu<T extends MenuItem> extends React.Component<Props<T>, State> {
|
|||||||
this.setState({ insertItem: item });
|
this.setState({ insertItem: item });
|
||||||
};
|
};
|
||||||
|
|
||||||
handleFilePicked = (event: React.ChangeEvent<HTMLInputElement>) => {
|
handleFilesPicked = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const files = getEventFiles(event);
|
const files = getEventFiles(event);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -581,7 +581,8 @@ class CommandMenu<T extends MenuItem> extends React.Component<Props<T>, State> {
|
|||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
ref={this.inputRef}
|
ref={this.inputRef}
|
||||||
onChange={this.handleFilePicked}
|
onChange={this.handleFilesPicked}
|
||||||
|
multiple
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</VisuallyHidden>
|
</VisuallyHidden>
|
||||||
|
|||||||
@@ -57,50 +57,62 @@ const insertFiles = function (
|
|||||||
|
|
||||||
// we'll use this to track of how many files have succeeded or failed
|
// we'll use this to track of how many files have succeeded or failed
|
||||||
let complete = 0;
|
let complete = 0;
|
||||||
|
let attachmentPlaceholdersSet = false;
|
||||||
|
|
||||||
|
const filesToUpload = files.map((file) => ({
|
||||||
|
id: `upload-${uuidv4()}`,
|
||||||
|
isImage: file.type.startsWith("image/") && !options.isAttachment,
|
||||||
|
file,
|
||||||
|
}));
|
||||||
|
|
||||||
// the user might have dropped multiple files at once, we need to loop
|
// the user might have dropped multiple files at once, we need to loop
|
||||||
for (const file of files) {
|
for (const upload of filesToUpload) {
|
||||||
const id = `upload-${uuidv4()}`;
|
|
||||||
const isImage = file.type.startsWith("image/") && !options.isAttachment;
|
|
||||||
const { tr } = view.state;
|
const { tr } = view.state;
|
||||||
|
|
||||||
if (isImage) {
|
if (upload.isImage) {
|
||||||
// insert a placeholder at this position, or mark an existing file as being
|
// insert a placeholder at this position, or mark an existing file as being
|
||||||
// replaced
|
// replaced
|
||||||
tr.setMeta(uploadPlaceholderPlugin, {
|
tr.setMeta(uploadPlaceholderPlugin, {
|
||||||
add: {
|
add: {
|
||||||
id,
|
id: upload.id,
|
||||||
file,
|
file: upload.file,
|
||||||
pos,
|
pos,
|
||||||
isImage,
|
isImage: true,
|
||||||
replaceExisting: options.replaceExisting,
|
replaceExisting: options.replaceExisting,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
view.dispatch(tr);
|
view.dispatch(tr);
|
||||||
} else {
|
} else if (!attachmentPlaceholdersSet) {
|
||||||
const $pos = tr.doc.resolve(pos);
|
const $pos = tr.doc.resolve(pos);
|
||||||
|
const attachmentsToUpload = filesToUpload.filter(
|
||||||
|
(i) => i.isImage === false
|
||||||
|
);
|
||||||
|
|
||||||
view.dispatch(
|
view.dispatch(
|
||||||
view.state.tr.replaceWith(
|
view.state.tr.replaceWith(
|
||||||
$pos.pos,
|
$pos.pos,
|
||||||
$pos.pos + ($pos.nodeAfter?.nodeSize || 0),
|
$pos.pos + ($pos.nodeAfter?.nodeSize || 0),
|
||||||
schema.nodes.attachment.create({
|
attachmentsToUpload.map((attachment) =>
|
||||||
id,
|
schema.nodes.attachment.create({
|
||||||
title: file.name ?? "Untitled",
|
id: attachment.id,
|
||||||
size: file.size,
|
title: attachment.file.name ?? "Untitled",
|
||||||
})
|
size: attachment.file.size,
|
||||||
|
})
|
||||||
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
attachmentPlaceholdersSet = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// start uploading the file to the server. Using "then" syntax
|
// start uploading the file to the server. Using "then" syntax
|
||||||
// to allow all placeholders to be entered at once with the uploads
|
// to allow all placeholders to be entered at once with the uploads
|
||||||
// happening in the background in parallel.
|
// happening in the background in parallel.
|
||||||
uploadFile(file)
|
uploadFile(upload.file)
|
||||||
.then((src) => {
|
.then((src) => {
|
||||||
if (isImage) {
|
if (upload.isImage) {
|
||||||
const newImg = new Image();
|
const newImg = new Image();
|
||||||
newImg.onload = () => {
|
newImg.onload = () => {
|
||||||
const result = findPlaceholder(view.state, id);
|
const result = findPlaceholder(view.state, upload.id);
|
||||||
|
|
||||||
// if the content around the placeholder has been deleted
|
// if the content around the placeholder has been deleted
|
||||||
// then forget about inserting this file
|
// then forget about inserting this file
|
||||||
@@ -116,7 +128,7 @@ const insertFiles = function (
|
|||||||
to || from,
|
to || from,
|
||||||
schema.nodes.image.create({ src, width: options.width })
|
schema.nodes.image.create({ src, width: options.width })
|
||||||
)
|
)
|
||||||
.setMeta(uploadPlaceholderPlugin, { remove: { id } })
|
.setMeta(uploadPlaceholderPlugin, { remove: { id: upload.id } })
|
||||||
);
|
);
|
||||||
|
|
||||||
// If the users selection is still at the file then make sure to select
|
// If the users selection is still at the file then make sure to select
|
||||||
@@ -137,7 +149,7 @@ const insertFiles = function (
|
|||||||
|
|
||||||
newImg.src = src;
|
newImg.src = src;
|
||||||
} else {
|
} else {
|
||||||
const result = findAttachmentById(view.state, id);
|
const result = findAttachmentById(view.state, upload.id);
|
||||||
|
|
||||||
// if the attachment has been deleted then forget about updating it
|
// if the attachment has been deleted then forget about updating it
|
||||||
if (result === null) {
|
if (result === null) {
|
||||||
@@ -151,8 +163,8 @@ const insertFiles = function (
|
|||||||
to || from,
|
to || from,
|
||||||
schema.nodes.attachment.create({
|
schema.nodes.attachment.create({
|
||||||
href: src,
|
href: src,
|
||||||
title: file.name ?? "Untitled",
|
title: upload.file.name ?? "Untitled",
|
||||||
size: file.size,
|
size: upload.file.size,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -173,14 +185,14 @@ const insertFiles = function (
|
|||||||
Sentry.captureException(error);
|
Sentry.captureException(error);
|
||||||
|
|
||||||
// cleanup the placeholder if there is a failure
|
// cleanup the placeholder if there is a failure
|
||||||
if (isImage) {
|
if (upload.isImage) {
|
||||||
view.dispatch(
|
view.dispatch(
|
||||||
view.state.tr.setMeta(uploadPlaceholderPlugin, {
|
view.state.tr.setMeta(uploadPlaceholderPlugin, {
|
||||||
remove: { id },
|
remove: { id: upload.id },
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const result = findAttachmentById(view.state, id);
|
const result = findAttachmentById(view.state, upload.id);
|
||||||
|
|
||||||
// if the attachment has been deleted then forget about updating it
|
// if the attachment has been deleted then forget about updating it
|
||||||
if (result === null) {
|
if (result === null) {
|
||||||
|
|||||||
Reference in New Issue
Block a user