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:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-03-04 18:16:11 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-03-04 18:16:11 +0300
commit73e15fde38825a490903ef88933d8896585f3008 (patch)
tree9540de3751be70a2f101185c8f830452d3a2ad1d /app/assets/javascripts/content_editor
parent7150920cea6cdd82b9409d5757fa26dac66876d1 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/content_editor')
-rw-r--r--app/assets/javascripts/content_editor/components/content_editor.vue28
-rw-r--r--app/assets/javascripts/content_editor/components/loading_indicator.vue39
-rw-r--r--app/assets/javascripts/content_editor/extensions/paste_markdown.js86
-rw-r--r--app/assets/javascripts/content_editor/extensions/table.js3
-rw-r--r--app/assets/javascripts/content_editor/services/create_content_editor.js2
-rw-r--r--app/assets/javascripts/content_editor/services/upload_helpers.js5
6 files changed, 138 insertions, 25 deletions
diff --git a/app/assets/javascripts/content_editor/components/content_editor.vue b/app/assets/javascripts/content_editor/components/content_editor.vue
index 7e9380ec553..a942c9f1149 100644
--- a/app/assets/javascripts/content_editor/components/content_editor.vue
+++ b/app/assets/javascripts/content_editor/components/content_editor.vue
@@ -1,5 +1,4 @@
<script>
-import { GlLoadingIcon } from '@gitlab/ui';
import { EditorContent as TiptapEditorContent } from '@tiptap/vue-2';
import { createContentEditor } from '../services/create_content_editor';
import ContentEditorAlert from './content_editor_alert.vue';
@@ -7,10 +6,11 @@ import ContentEditorProvider from './content_editor_provider.vue';
import EditorStateObserver from './editor_state_observer.vue';
import FormattingBubbleMenu from './formatting_bubble_menu.vue';
import TopToolbar from './top_toolbar.vue';
+import LoadingIndicator from './loading_indicator.vue';
export default {
components: {
- GlLoadingIcon,
+ LoadingIndicator,
ContentEditorAlert,
ContentEditorProvider,
TiptapEditorContent,
@@ -40,7 +40,6 @@ export default {
},
data() {
return {
- isLoadingContent: false,
focused: false,
};
},
@@ -62,12 +61,6 @@ export default {
this.contentEditor.dispose();
},
methods: {
- displayLoadingIndicator() {
- this.isLoadingContent = true;
- },
- hideLoadingIndicator() {
- this.isLoadingContent = false;
- },
focus() {
this.focused = true;
},
@@ -85,14 +78,7 @@ export default {
<template>
<content-editor-provider :content-editor="contentEditor">
<div>
- <editor-state-observer
- @loading="displayLoadingIndicator"
- @loadingSuccess="hideLoadingIndicator"
- @loadingError="hideLoadingIndicator"
- @docUpdate="notifyChange"
- @focus="focus"
- @blur="blur"
- />
+ <editor-state-observer @docUpdate="notifyChange" @focus="focus" @blur="blur" />
<content-editor-alert />
<div
data-testid="content-editor"
@@ -101,13 +87,11 @@ export default {
:class="{ 'is-focused': focused }"
>
<top-toolbar ref="toolbar" class="gl-mb-4" />
- <div v-if="isLoadingContent" class="gl-w-full gl-display-flex gl-justify-content-center">
- <gl-loading-icon size="sm" />
- </div>
- <template v-else>
+ <div class="gl-relative">
<formatting-bubble-menu />
<tiptap-editor-content class="md" :editor="contentEditor.tiptapEditor" />
- </template>
+ <loading-indicator />
+ </div>
</div>
</div>
</content-editor-provider>
diff --git a/app/assets/javascripts/content_editor/components/loading_indicator.vue b/app/assets/javascripts/content_editor/components/loading_indicator.vue
new file mode 100644
index 00000000000..5b9383d6e11
--- /dev/null
+++ b/app/assets/javascripts/content_editor/components/loading_indicator.vue
@@ -0,0 +1,39 @@
+<script>
+import { GlLoadingIcon } from '@gitlab/ui';
+import EditorStateObserver from './editor_state_observer.vue';
+
+export default {
+ components: {
+ GlLoadingIcon,
+ EditorStateObserver,
+ },
+ data() {
+ return {
+ isLoading: false,
+ };
+ },
+ methods: {
+ displayLoadingIndicator() {
+ this.isLoading = true;
+ },
+ hideLoadingIndicator() {
+ this.isLoading = false;
+ },
+ },
+};
+</script>
+<template>
+ <editor-state-observer
+ @loading="displayLoadingIndicator"
+ @loadingSuccess="hideLoadingIndicator"
+ @loadingError="hideLoadingIndicator"
+ >
+ <div
+ v-if="isLoading"
+ class="gl-w-full gl-display-flex gl-justify-content-center gl-align-items-center gl-absolute gl-top-0 gl-bottom-0"
+ >
+ <div class="gl-bg-white gl-absolute gl-w-full gl-h-full gl-opacity-3"></div>
+ <gl-loading-icon size="md" />
+ </div>
+ </editor-state-observer>
+</template>
diff --git a/app/assets/javascripts/content_editor/extensions/paste_markdown.js b/app/assets/javascripts/content_editor/extensions/paste_markdown.js
new file mode 100644
index 00000000000..31774e0ec51
--- /dev/null
+++ b/app/assets/javascripts/content_editor/extensions/paste_markdown.js
@@ -0,0 +1,86 @@
+import { Extension } from '@tiptap/core';
+import { Plugin, PluginKey } from 'prosemirror-state';
+import { __ } from '~/locale';
+import { VARIANT_DANGER } from '~/flash';
+import createMarkdownDeserializer from '../services/markdown_deserializer';
+import {
+ ALERT_EVENT,
+ LOADING_CONTENT_EVENT,
+ LOADING_SUCCESS_EVENT,
+ LOADING_ERROR_EVENT,
+ EXTENSION_PRIORITY_HIGHEST,
+} from '../constants';
+
+const TEXT_FORMAT = 'text/plain';
+const HTML_FORMAT = 'text/html';
+const VS_CODE_FORMAT = 'vscode-editor-data';
+
+export default Extension.create({
+ name: 'pasteMarkdown',
+ priority: EXTENSION_PRIORITY_HIGHEST,
+ addOptions() {
+ return {
+ renderMarkdown: null,
+ };
+ },
+ addCommands() {
+ return {
+ pasteMarkdown: (markdown) => () => {
+ const { editor, options } = this;
+ const { renderMarkdown, eventHub } = options;
+ const deserializer = createMarkdownDeserializer({ render: renderMarkdown });
+
+ eventHub.$emit(LOADING_CONTENT_EVENT);
+
+ deserializer
+ .deserialize({ schema: editor.schema, content: markdown })
+ .then((doc) => {
+ if (!doc) {
+ return;
+ }
+
+ const { state, view } = editor;
+ const { tr, selection } = state;
+
+ tr.replaceWith(selection.from - 1, selection.to, doc.content);
+ view.dispatch(tr);
+ eventHub.$emit(LOADING_SUCCESS_EVENT);
+ })
+ .catch(() => {
+ eventHub.$emit(ALERT_EVENT, {
+ message: __('An error occurred while pasting text in the editor. Please try again.'),
+ variant: VARIANT_DANGER,
+ });
+ eventHub.$emit(LOADING_ERROR_EVENT);
+ });
+
+ return true;
+ },
+ };
+ },
+ addProseMirrorPlugins() {
+ return [
+ new Plugin({
+ key: new PluginKey('pasteMarkdown'),
+ props: {
+ handlePaste: (_, event) => {
+ const { clipboardData } = event;
+ const content = clipboardData.getData(TEXT_FORMAT);
+ const hasHTML = clipboardData.types.some((type) => type === HTML_FORMAT);
+ const hasVsCode = clipboardData.types.some((type) => type === VS_CODE_FORMAT);
+ const vsCodeMeta = hasVsCode ? JSON.parse(clipboardData.getData(VS_CODE_FORMAT)) : {};
+ const language = vsCodeMeta.mode;
+
+ if (!content || (hasHTML && !hasVsCode) || (hasVsCode && language !== 'markdown')) {
+ return false;
+ }
+
+ this.editor.commands.pasteMarkdown(content);
+
+ return true;
+ },
+ },
+ }),
+ ];
+ },
+});
diff --git a/app/assets/javascripts/content_editor/extensions/table.js b/app/assets/javascripts/content_editor/extensions/table.js
index 004bb8b815c..d7456ab4094 100644
--- a/app/assets/javascripts/content_editor/extensions/table.js
+++ b/app/assets/javascripts/content_editor/extensions/table.js
@@ -1,5 +1,6 @@
import { Table } from '@tiptap/extension-table';
import { debounce } from 'lodash';
+import { VARIANT_WARNING } from '~/flash';
import { __ } from '~/locale';
import { getMarkdownSource } from '../services/markdown_sourcemap';
import { shouldRenderHTMLTable } from '../services/serialization_helpers';
@@ -14,7 +15,7 @@ const onUpdate = debounce((editor) => {
message: __(
'The content editor may change the markdown formatting style of the document, which may not match your original markdown style.',
),
- variant: 'warning',
+ variant: VARIANT_WARNING,
});
alertShown = true;
diff --git a/app/assets/javascripts/content_editor/services/create_content_editor.js b/app/assets/javascripts/content_editor/services/create_content_editor.js
index 354244b85ff..d9d39a387d0 100644
--- a/app/assets/javascripts/content_editor/services/create_content_editor.js
+++ b/app/assets/javascripts/content_editor/services/create_content_editor.js
@@ -39,6 +39,7 @@ import Loading from '../extensions/loading';
import MathInline from '../extensions/math_inline';
import OrderedList from '../extensions/ordered_list';
import Paragraph from '../extensions/paragraph';
+import PasteMarkdown from '../extensions/paste_markdown';
import Reference from '../extensions/reference';
import Strike from '../extensions/strike';
import Subscript from '../extensions/subscript';
@@ -120,6 +121,7 @@ export const createContentEditor = ({
MathInline,
OrderedList,
Paragraph,
+ PasteMarkdown.configure({ renderMarkdown, eventHub }),
Reference,
Strike,
Subscript,
diff --git a/app/assets/javascripts/content_editor/services/upload_helpers.js b/app/assets/javascripts/content_editor/services/upload_helpers.js
index 33e9f455ef8..1abecb8f414 100644
--- a/app/assets/javascripts/content_editor/services/upload_helpers.js
+++ b/app/assets/javascripts/content_editor/services/upload_helpers.js
@@ -1,3 +1,4 @@
+import { VARIANT_DANGER } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
import { extractFilename, readFileAsDataURL } from './utils';
@@ -74,7 +75,7 @@ const uploadImage = async ({ editor, file, uploadsPath, renderMarkdown, eventHub
editor.commands.deleteRange({ from: position, to: position + 1 });
eventHub.$emit('alert', {
message: __('An error occurred while uploading the image. Please try again.'),
- variant: 'danger',
+ variant: VARIANT_DANGER,
});
}
};
@@ -105,7 +106,7 @@ const uploadAttachment = async ({ editor, file, uploadsPath, renderMarkdown, eve
editor.commands.deleteRange({ from, to: from + 1 });
eventHub.$emit('alert', {
message: __('An error occurred while uploading the file. Please try again.'),
- variant: 'danger',
+ variant: VARIANT_DANGER,
});
}
};