126 lines
3.8 KiB
JavaScript
126 lines
3.8 KiB
JavaScript
import axios from '~/lib/utils/axios_utils';
|
|
import { __ } from '~/locale';
|
|
import { extractFilename, readFileAsDataURL } from './utils';
|
|
|
|
export const acceptedMimes = {
|
|
image: ['image/jpeg', 'image/png', 'image/gif', 'image/jpg'],
|
|
};
|
|
|
|
const extractAttachmentLinkUrl = (html) => {
|
|
const parser = new DOMParser();
|
|
const { body } = parser.parseFromString(html, 'text/html');
|
|
const link = body.querySelector('a');
|
|
const src = link.getAttribute('href');
|
|
const { canonicalSrc } = link.dataset;
|
|
|
|
return { src, canonicalSrc };
|
|
};
|
|
|
|
/**
|
|
* Uploads a file with a post request to the URL indicated
|
|
* in the uploadsPath parameter. The expected response of the
|
|
* uploads service is a JSON object that contains, at least, a
|
|
* link property. The link property should contain markdown link
|
|
* definition (i.e. [GitLab](https://gitlab.com)).
|
|
*
|
|
* This Markdown will be rendered to extract its canonical and full
|
|
* URLs using GitLab Flavored Markdown renderer in the backend.
|
|
*
|
|
* @param {Object} params
|
|
* @param {String} params.uploadsPath An absolute URL that points to a service
|
|
* that allows sending a file for uploading via POST request.
|
|
* @param {String} params.renderMarkdown A function that accepts a markdown string
|
|
* and returns a rendered version in HTML format.
|
|
* @param {File} params.file The file to upload
|
|
*
|
|
* @returns Returns an object with two properties:
|
|
*
|
|
* canonicalSrc: The URL as defined in the Markdown
|
|
* src: The absolute URL that points to the resource in the server
|
|
*/
|
|
export const uploadFile = async ({ uploadsPath, renderMarkdown, file }) => {
|
|
const formData = new FormData();
|
|
formData.append('file', file, file.name);
|
|
|
|
const { data } = await axios.post(uploadsPath, formData);
|
|
const { markdown } = data.link;
|
|
const rendered = await renderMarkdown(markdown);
|
|
|
|
return extractAttachmentLinkUrl(rendered);
|
|
};
|
|
|
|
const uploadImage = async ({ editor, file, uploadsPath, renderMarkdown, eventHub }) => {
|
|
const encodedSrc = await readFileAsDataURL(file);
|
|
const { view } = editor;
|
|
|
|
editor.commands.setImage({ uploading: true, src: encodedSrc });
|
|
|
|
const { state } = view;
|
|
const position = state.selection.from - 1;
|
|
const { tr } = state;
|
|
|
|
try {
|
|
const { src, canonicalSrc } = await uploadFile({ file, uploadsPath, renderMarkdown });
|
|
|
|
view.dispatch(
|
|
tr.setNodeMarkup(position, undefined, {
|
|
uploading: false,
|
|
src: encodedSrc,
|
|
alt: extractFilename(src),
|
|
canonicalSrc,
|
|
}),
|
|
);
|
|
} catch (e) {
|
|
editor.commands.deleteRange({ from: position, to: position + 1 });
|
|
eventHub.$emit('alert', {
|
|
message: __('An error occurred while uploading the image. Please try again.'),
|
|
variant: 'danger',
|
|
});
|
|
}
|
|
};
|
|
|
|
const uploadAttachment = async ({ editor, file, uploadsPath, renderMarkdown, eventHub }) => {
|
|
await Promise.resolve();
|
|
|
|
const { view } = editor;
|
|
|
|
const text = extractFilename(file.name);
|
|
|
|
const { state } = view;
|
|
const { from } = state.selection;
|
|
|
|
editor.commands.insertContent({
|
|
type: 'loading',
|
|
attrs: { label: text },
|
|
});
|
|
|
|
try {
|
|
const { src, canonicalSrc } = await uploadFile({ file, uploadsPath, renderMarkdown });
|
|
|
|
editor.commands.insertContentAt(
|
|
{ from, to: from + 1 },
|
|
{ type: 'text', text, marks: [{ type: 'link', attrs: { href: src, canonicalSrc } }] },
|
|
);
|
|
} catch (e) {
|
|
editor.commands.deleteRange({ from, to: from + 1 });
|
|
eventHub.$emit('alert', {
|
|
message: __('An error occurred while uploading the file. Please try again.'),
|
|
variant: 'danger',
|
|
});
|
|
}
|
|
};
|
|
|
|
export const handleFileEvent = ({ editor, file, uploadsPath, renderMarkdown, eventHub }) => {
|
|
if (!file) return false;
|
|
|
|
if (acceptedMimes.image.includes(file?.type)) {
|
|
uploadImage({ editor, file, uploadsPath, renderMarkdown, eventHub });
|
|
|
|
return true;
|
|
}
|
|
|
|
uploadAttachment({ editor, file, uploadsPath, renderMarkdown, eventHub });
|
|
|
|
return true;
|
|
};
|