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>2021-11-17 18:10:28 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-11-17 18:10:28 +0300
commita331169e6e84f93fd9b841b56465ac113b6d03f9 (patch)
tree1e823b05f484f55a5f7663b9aa580b64f6c6e0fd /app/assets/javascripts/content_editor
parentc609c898ff7f42c3d72a1c6d619e1ff786f5e18a (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.vue6
-rw-r--r--app/assets/javascripts/content_editor/components/content_editor_alert.vue33
-rw-r--r--app/assets/javascripts/content_editor/components/content_editor_error.vue31
-rw-r--r--app/assets/javascripts/content_editor/components/editor_state_observer.vue2
-rw-r--r--app/assets/javascripts/content_editor/components/wrappers/table_cell_base.vue22
-rw-r--r--app/assets/javascripts/content_editor/components/wrappers/table_cell_body.vue4
-rw-r--r--app/assets/javascripts/content_editor/components/wrappers/table_cell_header.vue4
-rw-r--r--app/assets/javascripts/content_editor/extensions/table.js43
-rw-r--r--app/assets/javascripts/content_editor/extensions/table_cell.js3
-rw-r--r--app/assets/javascripts/content_editor/extensions/table_header.js3
-rw-r--r--app/assets/javascripts/content_editor/services/feature_flags.js3
-rw-r--r--app/assets/javascripts/content_editor/services/serialization_helpers.js16
-rw-r--r--app/assets/javascripts/content_editor/services/upload_helpers.js10
13 files changed, 112 insertions, 68 deletions
diff --git a/app/assets/javascripts/content_editor/components/content_editor.vue b/app/assets/javascripts/content_editor/components/content_editor.vue
index 02ab34447ca..a8405fe37c7 100644
--- a/app/assets/javascripts/content_editor/components/content_editor.vue
+++ b/app/assets/javascripts/content_editor/components/content_editor.vue
@@ -3,7 +3,7 @@ import { GlLoadingIcon } from '@gitlab/ui';
import { EditorContent as TiptapEditorContent } from '@tiptap/vue-2';
import { LOADING_CONTENT_EVENT, LOADING_SUCCESS_EVENT, LOADING_ERROR_EVENT } from '../constants';
import { createContentEditor } from '../services/create_content_editor';
-import ContentEditorError from './content_editor_error.vue';
+import ContentEditorAlert from './content_editor_alert.vue';
import ContentEditorProvider from './content_editor_provider.vue';
import EditorStateObserver from './editor_state_observer.vue';
import FormattingBubbleMenu from './formatting_bubble_menu.vue';
@@ -12,7 +12,7 @@ import TopToolbar from './top_toolbar.vue';
export default {
components: {
GlLoadingIcon,
- ContentEditorError,
+ ContentEditorAlert,
ContentEditorProvider,
TiptapEditorContent,
TopToolbar,
@@ -92,7 +92,7 @@ export default {
<content-editor-provider :content-editor="contentEditor">
<div>
<editor-state-observer @docUpdate="notifyChange" @focus="focus" @blur="blur" />
- <content-editor-error />
+ <content-editor-alert />
<div
data-testid="content-editor"
data-qa-selector="content_editor_container"
diff --git a/app/assets/javascripts/content_editor/components/content_editor_alert.vue b/app/assets/javascripts/content_editor/components/content_editor_alert.vue
new file mode 100644
index 00000000000..c6737da1d77
--- /dev/null
+++ b/app/assets/javascripts/content_editor/components/content_editor_alert.vue
@@ -0,0 +1,33 @@
+<script>
+import { GlAlert } from '@gitlab/ui';
+import EditorStateObserver from './editor_state_observer.vue';
+
+export default {
+ components: {
+ GlAlert,
+ EditorStateObserver,
+ },
+ data() {
+ return {
+ message: null,
+ variant: 'danger',
+ };
+ },
+ methods: {
+ displayAlert({ message, variant }) {
+ this.message = message;
+ this.variant = variant;
+ },
+ dismissAlert() {
+ this.message = null;
+ },
+ },
+};
+</script>
+<template>
+ <editor-state-observer @alert="displayAlert">
+ <gl-alert v-if="message" class="gl-mb-6" :variant="variant" @dismiss="dismissAlert">
+ {{ message }}
+ </gl-alert>
+ </editor-state-observer>
+</template>
diff --git a/app/assets/javascripts/content_editor/components/content_editor_error.vue b/app/assets/javascripts/content_editor/components/content_editor_error.vue
deleted file mode 100644
index 031ea92a7e9..00000000000
--- a/app/assets/javascripts/content_editor/components/content_editor_error.vue
+++ /dev/null
@@ -1,31 +0,0 @@
-<script>
-import { GlAlert } from '@gitlab/ui';
-import EditorStateObserver from './editor_state_observer.vue';
-
-export default {
- components: {
- GlAlert,
- EditorStateObserver,
- },
- data() {
- return {
- error: null,
- };
- },
- methods: {
- displayError({ error }) {
- this.error = error;
- },
- dismissError() {
- this.error = null;
- },
- },
-};
-</script>
-<template>
- <editor-state-observer @error="displayError">
- <gl-alert v-if="error" class="gl-mb-6" variant="danger" @dismiss="dismissError">
- {{ error }}
- </gl-alert>
- </editor-state-observer>
-</template>
diff --git a/app/assets/javascripts/content_editor/components/editor_state_observer.vue b/app/assets/javascripts/content_editor/components/editor_state_observer.vue
index 2eeb0719096..0604047a953 100644
--- a/app/assets/javascripts/content_editor/components/editor_state_observer.vue
+++ b/app/assets/javascripts/content_editor/components/editor_state_observer.vue
@@ -7,7 +7,7 @@ export const tiptapToComponentMap = {
transaction: 'transaction',
focus: 'focus',
blur: 'blur',
- error: 'error',
+ alert: 'alert',
};
const getComponentEventName = (tiptapEventName) => tiptapToComponentMap[tiptapEventName];
diff --git a/app/assets/javascripts/content_editor/components/wrappers/table_cell_base.vue b/app/assets/javascripts/content_editor/components/wrappers/table_cell_base.vue
index c44e8145982..41c083111c5 100644
--- a/app/assets/javascripts/content_editor/components/wrappers/table_cell_base.vue
+++ b/app/assets/javascripts/content_editor/components/wrappers/table_cell_base.vue
@@ -26,8 +26,8 @@ export default {
type: Object,
required: true,
},
- getPos: {
- type: Function,
+ node: {
+ type: Object,
required: true,
},
},
@@ -61,7 +61,17 @@ export default {
const { state } = this.editor;
const { $cursor } = state.selection;
- this.displayActionsDropdown = $cursor?.pos - $cursor?.parentOffset - 1 === this.getPos();
+ if (!$cursor) return;
+
+ this.displayActionsDropdown = false;
+
+ for (let level = 0; level < $cursor.depth; level += 1) {
+ if ($cursor.node(level) === this.node) {
+ this.displayActionsDropdown = true;
+ break;
+ }
+ }
+
if (this.displayActionsDropdown) {
this.selectedRect = getSelectedRect(state);
}
@@ -99,7 +109,11 @@ export default {
:as="cellType"
@click="hideDropdown"
>
- <span v-if="displayActionsDropdown" class="gl-absolute gl-right-0 gl-top-0">
+ <span
+ v-if="displayActionsDropdown"
+ contenteditable="false"
+ class="gl-absolute gl-right-0 gl-top-0"
+ >
<gl-dropdown
ref="dropdown"
dropup
diff --git a/app/assets/javascripts/content_editor/components/wrappers/table_cell_body.vue b/app/assets/javascripts/content_editor/components/wrappers/table_cell_body.vue
index 6b4343dd5b8..47cd837d060 100644
--- a/app/assets/javascripts/content_editor/components/wrappers/table_cell_body.vue
+++ b/app/assets/javascripts/content_editor/components/wrappers/table_cell_body.vue
@@ -11,8 +11,8 @@ export default {
type: Object,
required: true,
},
- getPos: {
- type: Function,
+ node: {
+ type: Object,
required: true,
},
},
diff --git a/app/assets/javascripts/content_editor/components/wrappers/table_cell_header.vue b/app/assets/javascripts/content_editor/components/wrappers/table_cell_header.vue
index 5f9889374f6..150f78bc84f 100644
--- a/app/assets/javascripts/content_editor/components/wrappers/table_cell_header.vue
+++ b/app/assets/javascripts/content_editor/components/wrappers/table_cell_header.vue
@@ -11,8 +11,8 @@ export default {
type: Object,
required: true,
},
- getPos: {
- type: Function,
+ node: {
+ type: Object,
required: true,
},
},
diff --git a/app/assets/javascripts/content_editor/extensions/table.js b/app/assets/javascripts/content_editor/extensions/table.js
index 0f0477cba2e..004bb8b815c 100644
--- a/app/assets/javascripts/content_editor/extensions/table.js
+++ b/app/assets/javascripts/content_editor/extensions/table.js
@@ -1 +1,42 @@
-export { Table as default } from '@tiptap/extension-table';
+import { Table } from '@tiptap/extension-table';
+import { debounce } from 'lodash';
+import { __ } from '~/locale';
+import { getMarkdownSource } from '../services/markdown_sourcemap';
+import { shouldRenderHTMLTable } from '../services/serialization_helpers';
+
+let alertShown = false;
+const onUpdate = debounce((editor) => {
+ if (alertShown) return;
+
+ editor.state.doc.descendants((node) => {
+ if (node.type.name === 'table' && node.attrs.isMarkdown && shouldRenderHTMLTable(node)) {
+ editor.emit('alert', {
+ message: __(
+ 'The content editor may change the markdown formatting style of the document, which may not match your original markdown style.',
+ ),
+ variant: 'warning',
+ });
+
+ alertShown = true;
+
+ return false;
+ }
+
+ return true;
+ });
+}, 1000);
+
+export default Table.extend({
+ addAttributes() {
+ return {
+ isMarkdown: {
+ default: null,
+ parseHTML: (element) => Boolean(getMarkdownSource(element)),
+ },
+ };
+ },
+
+ onUpdate({ editor }) {
+ onUpdate(editor);
+ },
+});
diff --git a/app/assets/javascripts/content_editor/extensions/table_cell.js b/app/assets/javascripts/content_editor/extensions/table_cell.js
index befc33e669f..9f437ce066c 100644
--- a/app/assets/javascripts/content_editor/extensions/table_cell.js
+++ b/app/assets/javascripts/content_editor/extensions/table_cell.js
@@ -1,10 +1,9 @@
import { TableCell } from '@tiptap/extension-table-cell';
import { VueNodeViewRenderer } from '@tiptap/vue-2';
import TableCellBodyWrapper from '../components/wrappers/table_cell_body.vue';
-import { isBlockTablesFeatureEnabled } from '../services/feature_flags';
export default TableCell.extend({
- content: isBlockTablesFeatureEnabled() ? 'block+' : 'inline*',
+ content: 'block+',
addNodeView() {
return VueNodeViewRenderer(TableCellBodyWrapper);
diff --git a/app/assets/javascripts/content_editor/extensions/table_header.js b/app/assets/javascripts/content_editor/extensions/table_header.js
index 829b06fc14b..045fd03199b 100644
--- a/app/assets/javascripts/content_editor/extensions/table_header.js
+++ b/app/assets/javascripts/content_editor/extensions/table_header.js
@@ -1,10 +1,9 @@
import { TableHeader } from '@tiptap/extension-table-header';
import { VueNodeViewRenderer } from '@tiptap/vue-2';
import TableCellHeaderWrapper from '../components/wrappers/table_cell_header.vue';
-import { isBlockTablesFeatureEnabled } from '../services/feature_flags';
export default TableHeader.extend({
- content: isBlockTablesFeatureEnabled() ? 'block+' : 'inline*',
+ content: 'block+',
addNodeView() {
return VueNodeViewRenderer(TableCellHeaderWrapper);
},
diff --git a/app/assets/javascripts/content_editor/services/feature_flags.js b/app/assets/javascripts/content_editor/services/feature_flags.js
deleted file mode 100644
index 5f7a4595938..00000000000
--- a/app/assets/javascripts/content_editor/services/feature_flags.js
+++ /dev/null
@@ -1,3 +0,0 @@
-export function isBlockTablesFeatureEnabled() {
- return gon.features?.contentEditorBlockTables;
-}
diff --git a/app/assets/javascripts/content_editor/services/serialization_helpers.js b/app/assets/javascripts/content_editor/services/serialization_helpers.js
index b2327555b45..ed5910fca18 100644
--- a/app/assets/javascripts/content_editor/services/serialization_helpers.js
+++ b/app/assets/javascripts/content_editor/services/serialization_helpers.js
@@ -1,5 +1,4 @@
import { uniq } from 'lodash';
-import { isBlockTablesFeatureEnabled } from './feature_flags';
const defaultAttrs = {
td: { colspan: 1, rowspan: 1, colwidth: null },
@@ -75,7 +74,7 @@ function getChildren(node) {
return children;
}
-function shouldRenderHTMLTable(table) {
+export function shouldRenderHTMLTable(table) {
const { rows, cells } = getRowsAndCells(table);
const cellChildCount = Math.max(...cells.map((cell) => cell.childCount));
@@ -282,11 +281,6 @@ export function renderOrderedList(state, node) {
}
export function renderTableCell(state, node) {
- if (!isBlockTablesFeatureEnabled()) {
- state.renderInline(node);
- return;
- }
-
if (!isInBlockTable(node) || containsParagraphWithOnlyText(node)) {
state.renderInline(node.child(0));
} else {
@@ -303,9 +297,7 @@ export function renderTableRow(state, node) {
}
export function renderTable(state, node) {
- if (isBlockTablesFeatureEnabled()) {
- setIsInBlockTable(node, shouldRenderHTMLTable(node));
- }
+ setIsInBlockTable(node, shouldRenderHTMLTable(node));
if (isInBlockTable(node)) renderTagOpen(state, 'table');
@@ -317,9 +309,7 @@ export function renderTable(state, node) {
state.closeBlock(node);
state.flushClose();
- if (isBlockTablesFeatureEnabled()) {
- unsetIsInBlockTable(node);
- }
+ unsetIsInBlockTable(node);
}
export function renderHardBreak(state, node, parent, index) {
diff --git a/app/assets/javascripts/content_editor/services/upload_helpers.js b/app/assets/javascripts/content_editor/services/upload_helpers.js
index 8ac3f719309..f5bf2742748 100644
--- a/app/assets/javascripts/content_editor/services/upload_helpers.js
+++ b/app/assets/javascripts/content_editor/services/upload_helpers.js
@@ -72,8 +72,9 @@ const uploadImage = async ({ editor, file, uploadsPath, renderMarkdown }) => {
);
} catch (e) {
editor.commands.deleteRange({ from: position, to: position + 1 });
- editor.emit('error', {
- error: __('An error occurred while uploading the image. Please try again.'),
+ editor.emit('alert', {
+ message: __('An error occurred while uploading the image. Please try again.'),
+ variant: 'danger',
});
}
};
@@ -102,8 +103,9 @@ const uploadAttachment = async ({ editor, file, uploadsPath, renderMarkdown }) =
);
} catch (e) {
editor.commands.deleteRange({ from, to: from + 1 });
- editor.emit('error', {
- error: __('An error occurred while uploading the file. Please try again.'),
+ editor.emit('alert', {
+ message: __('An error occurred while uploading the file. Please try again.'),
+ variant: 'danger',
});
}
};