Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/content_editor/services/upload_helpers.js')
-rw-r--r--app/assets/javascripts/content_editor/services/upload_helpers.js123
1 files changed, 123 insertions, 0 deletions
diff --git a/app/assets/javascripts/content_editor/services/upload_helpers.js b/app/assets/javascripts/content_editor/services/upload_helpers.js
new file mode 100644
index 00000000000..8ac3f719309
--- /dev/null
+++ b/app/assets/javascripts/content_editor/services/upload_helpers.js
@@ -0,0 +1,123 @@
+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 }) => {
+ 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 });
+ editor.emit('error', {
+ error: __('An error occurred while uploading the image. Please try again.'),
+ });
+ }
+};
+
+const uploadAttachment = async ({ editor, file, uploadsPath, renderMarkdown }) => {
+ 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 });
+ editor.emit('error', {
+ error: __('An error occurred while uploading the file. Please try again.'),
+ });
+ }
+};
+
+export const handleFileEvent = ({ editor, file, uploadsPath, renderMarkdown }) => {
+ if (!file) return false;
+
+ if (acceptedMimes.image.includes(file?.type)) {
+ uploadImage({ editor, file, uploadsPath, renderMarkdown });
+
+ return true;
+ }
+
+ uploadAttachment({ editor, file, uploadsPath, renderMarkdown });
+
+ return true;
+};