diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-11-18 16:16:36 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-11-18 16:16:36 +0300 |
commit | 311b0269b4eb9839fa63f80c8d7a58f32b8138a0 (patch) | |
tree | 07e7870bca8aed6d61fdcc810731c50d2c40af47 /app/assets/javascripts/content_editor | |
parent | 27909cef6c4170ed9205afa7426b8d3de47cbb0c (diff) |
Add latest changes from gitlab-org/gitlab@14-5-stable-eev14.5.0-rc42
Diffstat (limited to 'app/assets/javascripts/content_editor')
28 files changed, 230 insertions, 141 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/blockquote.js b/app/assets/javascripts/content_editor/extensions/blockquote.js index 4512ead44bc..5632bc28592 100644 --- a/app/assets/javascripts/content_editor/extensions/blockquote.js +++ b/app/assets/javascripts/content_editor/extensions/blockquote.js @@ -1,10 +1,8 @@ import { Blockquote } from '@tiptap/extension-blockquote'; -import { wrappingInputRule } from 'prosemirror-inputrules'; +import { wrappingInputRule } from '@tiptap/core'; import { getParents } from '~/lib/utils/dom_utils'; import { getMarkdownSource } from '../services/markdown_sourcemap'; -export const multilineInputRegex = /^\s*>>>\s$/gm; - export default Blockquote.extend({ addAttributes() { return { @@ -25,9 +23,15 @@ export default Blockquote.extend({ }, addInputRules() { + const multilineInputRegex = /^\s*>>>\s$/gm; + return [ ...this.parent?.(), - wrappingInputRule(multilineInputRegex, this.type, () => ({ multiline: true })), + wrappingInputRule({ + find: multilineInputRegex, + type: this.type, + getAttributes: () => ({ multiline: true }), + }), ]; }, }); diff --git a/app/assets/javascripts/content_editor/extensions/description_list.js b/app/assets/javascripts/content_editor/extensions/description_list.js index a516dfad2b8..8f5b145cfa3 100644 --- a/app/assets/javascripts/content_editor/extensions/description_list.js +++ b/app/assets/javascripts/content_editor/extensions/description_list.js @@ -1,7 +1,4 @@ -import { Node, mergeAttributes } from '@tiptap/core'; -import { wrappingInputRule } from 'prosemirror-inputrules'; - -export const inputRegex = /^\s*(<dl>)$/; +import { Node, mergeAttributes, wrappingInputRule } from '@tiptap/core'; export default Node.create({ name: 'descriptionList', @@ -18,6 +15,8 @@ export default Node.create({ }, addInputRules() { - return [wrappingInputRule(inputRegex, this.type)]; + const inputRegex = /^\s*(<dl>)$/; + + return [wrappingInputRule({ find: inputRegex, type: this.type })]; }, }); diff --git a/app/assets/javascripts/content_editor/extensions/details.js b/app/assets/javascripts/content_editor/extensions/details.js index e3d54ed01fd..46c906d45b1 100644 --- a/app/assets/javascripts/content_editor/extensions/details.js +++ b/app/assets/javascripts/content_editor/extensions/details.js @@ -1,10 +1,7 @@ -import { Node } from '@tiptap/core'; +import { Node, wrappingInputRule } from '@tiptap/core'; import { VueNodeViewRenderer } from '@tiptap/vue-2'; -import { wrappingInputRule } from 'prosemirror-inputrules'; import DetailsWrapper from '../components/wrappers/details.vue'; -export const inputRegex = /^\s*(<details>)$/; - export default Node.create({ name: 'details', content: 'detailsContent+', @@ -24,7 +21,9 @@ export default Node.create({ }, addInputRules() { - return [wrappingInputRule(inputRegex, this.type)]; + const inputRegex = /^\s*(<details>)$/; + + return [wrappingInputRule({ find: inputRegex, type: this.type })]; }, addCommands() { diff --git a/app/assets/javascripts/content_editor/extensions/emoji.js b/app/assets/javascripts/content_editor/extensions/emoji.js index de608c3aaa2..7f8b5da5f46 100644 --- a/app/assets/javascripts/content_editor/extensions/emoji.js +++ b/app/assets/javascripts/content_editor/extensions/emoji.js @@ -1,9 +1,6 @@ -import { Node } from '@tiptap/core'; -import { InputRule } from 'prosemirror-inputrules'; +import { Node, InputRule } from '@tiptap/core'; import { initEmojiMap, getAllEmoji } from '~/emoji'; -export const emojiInputRegex = /(?:^|\s)((?::)((?:\w+))(?::))$/; - export default Node.create({ name: 'emoji', @@ -54,23 +51,28 @@ export default Node.create({ }, addInputRules() { + const emojiInputRegex = /(?:^|\s)(:(\w+):)$/; + return [ - new InputRule(emojiInputRegex, (state, match, start, end) => { - const [, , name] = match; - const emojis = getAllEmoji(); - const emoji = emojis[name]; - const { tr } = state; + new InputRule({ + find: emojiInputRegex, + handler: ({ state, range: { from, to }, match }) => { + const [, , name] = match; + const emojis = getAllEmoji(); + const emoji = emojis[name]; + const { tr } = state; - if (emoji) { - tr.replaceWith(start, end, [ - state.schema.text(' '), - this.type.create({ name, moji: emoji.e, unicodeVersion: emoji.u, title: emoji.d }), - ]); + if (emoji) { + tr.replaceWith(from, to, [ + state.schema.text(' '), + this.type.create({ name, moji: emoji.e, unicodeVersion: emoji.u, title: emoji.d }), + ]); - return tr; - } + return tr; + } - return null; + return null; + }, }), ]; }, diff --git a/app/assets/javascripts/content_editor/extensions/frontmatter.js b/app/assets/javascripts/content_editor/extensions/frontmatter.js index 64c84fe046b..c09c10bc524 100644 --- a/app/assets/javascripts/content_editor/extensions/frontmatter.js +++ b/app/assets/javascripts/content_editor/extensions/frontmatter.js @@ -17,4 +17,7 @@ export default CodeBlockHighlight.extend({ addNodeView() { return new VueNodeViewRenderer(FrontmatterWrapper); }, + addInputRules() { + return []; + }, }); diff --git a/app/assets/javascripts/content_editor/extensions/horizontal_rule.js b/app/assets/javascripts/content_editor/extensions/horizontal_rule.js index c8ec45d835c..c4f31e5f981 100644 --- a/app/assets/javascripts/content_editor/extensions/horizontal_rule.js +++ b/app/assets/javascripts/content_editor/extensions/horizontal_rule.js @@ -1,10 +1,10 @@ import { nodeInputRule } from '@tiptap/core'; import { HorizontalRule } from '@tiptap/extension-horizontal-rule'; -export const hrInputRuleRegExp = /^---$/; - export default HorizontalRule.extend({ addInputRules() { - return [nodeInputRule(hrInputRuleRegExp, this.type)]; + const hrInputRuleRegExp = /^---$/; + + return [nodeInputRule({ find: hrInputRuleRegExp, type: this.type })]; }, }); diff --git a/app/assets/javascripts/content_editor/extensions/html_marks.js b/app/assets/javascripts/content_editor/extensions/html_marks.js index 54adb9efa0c..3abf0e3eee2 100644 --- a/app/assets/javascripts/content_editor/extensions/html_marks.js +++ b/app/assets/javascripts/content_editor/extensions/html_marks.js @@ -60,7 +60,13 @@ export default marks.map((name) => }, addInputRules() { - return [markInputRule(markInputRegex(name), this.type, extractMarkAttributesFromMatch)]; + return [ + markInputRule({ + find: markInputRegex(name), + type: this.type, + getAttributes: extractMarkAttributesFromMatch, + }), + ]; }, }), ); diff --git a/app/assets/javascripts/content_editor/extensions/inline_diff.js b/app/assets/javascripts/content_editor/extensions/inline_diff.js index 3bd328958df..22bb1ac072e 100644 --- a/app/assets/javascripts/content_editor/extensions/inline_diff.js +++ b/app/assets/javascripts/content_editor/extensions/inline_diff.js @@ -1,8 +1,5 @@ import { Mark, markInputRule, mergeAttributes } from '@tiptap/core'; -export const inputRegexAddition = /(\{\+(.+?)\+\})$/gm; -export const inputRegexDeletion = /(\{-(.+?)-\})$/gm; - export default Mark.create({ name: 'inlineDiff', @@ -38,9 +35,20 @@ export default Mark.create({ }, addInputRules() { + const inputRegexAddition = /(\{\+(.+?)\+\})$/gm; + const inputRegexDeletion = /(\{-(.+?)-\})$/gm; + return [ - markInputRule(inputRegexAddition, this.type, () => ({ type: 'addition' })), - markInputRule(inputRegexDeletion, this.type, () => ({ type: 'deletion' })), + markInputRule({ + find: inputRegexAddition, + type: this.type, + getAttributes: () => ({ type: 'addition' }), + }), + markInputRule({ + find: inputRegexDeletion, + type: this.type, + getAttributes: () => ({ type: 'deletion' }), + }), ]; }, }); diff --git a/app/assets/javascripts/content_editor/extensions/link.js b/app/assets/javascripts/content_editor/extensions/link.js index fc0f38e6935..27bc05dce6f 100644 --- a/app/assets/javascripts/content_editor/extensions/link.js +++ b/app/assets/javascripts/content_editor/extensions/link.js @@ -1,9 +1,6 @@ import { markInputRule } from '@tiptap/core'; import { Link } from '@tiptap/extension-link'; -export const markdownLinkSyntaxInputRuleRegExp = /(?:^|\s)\[([\w|\s|-]+)\]\((?<href>.+?)\)$/gm; -export const urlSyntaxRegExp = /(?:^|\s)(?<href>(?:https?:\/\/|www\.)[\S]+)(?:\s|\n)$/gim; - const extractHrefFromMatch = (match) => { return { href: match.groups.href }; }; @@ -26,9 +23,20 @@ export default Link.extend({ openOnClick: false, }, addInputRules() { + const markdownLinkSyntaxInputRuleRegExp = /(?:^|\s)\[([\w|\s|-]+)\]\((?<href>.+?)\)$/gm; + const urlSyntaxRegExp = /(?:^|\s)(?<href>(?:https?:\/\/|www\.)[\S]+)(?:\s|\n)$/gim; + return [ - markInputRule(markdownLinkSyntaxInputRuleRegExp, this.type, extractHrefFromMarkdownLink), - markInputRule(urlSyntaxRegExp, this.type, extractHrefFromMatch), + markInputRule({ + find: markdownLinkSyntaxInputRuleRegExp, + type: this.type, + getAttributes: extractHrefFromMarkdownLink, + }), + markInputRule({ + find: urlSyntaxRegExp, + type: this.type, + getAttributes: extractHrefFromMatch, + }), ]; }, addAttributes() { diff --git a/app/assets/javascripts/content_editor/extensions/math_inline.js b/app/assets/javascripts/content_editor/extensions/math_inline.js index 60f5288dcf6..4844f6feb29 100644 --- a/app/assets/javascripts/content_editor/extensions/math_inline.js +++ b/app/assets/javascripts/content_editor/extensions/math_inline.js @@ -2,8 +2,6 @@ import { Mark, markInputRule } from '@tiptap/core'; import { __ } from '~/locale'; import { PARSE_HTML_PRIORITY_HIGHEST } from '../constants'; -export const inputRegex = /(?:^|\s)\$`([^`]+)`\$$/gm; - export default Mark.create({ name: 'mathInline', @@ -30,6 +28,8 @@ export default Mark.create({ }, addInputRules() { - return [markInputRule(inputRegex, this.type)]; + const inputRegex = /(?:^|\s)\$`([^`]+)`\$$/gm; + + return [markInputRule({ find: inputRegex, type: this.type })]; }, }); diff --git a/app/assets/javascripts/content_editor/extensions/subscript.js b/app/assets/javascripts/content_editor/extensions/subscript.js index d0766f42308..a8c087e8bf0 100644 --- a/app/assets/javascripts/content_editor/extensions/subscript.js +++ b/app/assets/javascripts/content_editor/extensions/subscript.js @@ -4,6 +4,12 @@ import { markInputRegex, extractMarkAttributesFromMatch } from '../services/mark export default Subscript.extend({ addInputRules() { - return [markInputRule(markInputRegex('sub'), this.type, extractMarkAttributesFromMatch)]; + return [ + markInputRule({ + find: markInputRegex('sub'), + type: this.type, + getAttributes: extractMarkAttributesFromMatch, + }), + ]; }, }); diff --git a/app/assets/javascripts/content_editor/extensions/superscript.js b/app/assets/javascripts/content_editor/extensions/superscript.js index 6cd814977ea..b86906f01f2 100644 --- a/app/assets/javascripts/content_editor/extensions/superscript.js +++ b/app/assets/javascripts/content_editor/extensions/superscript.js @@ -4,6 +4,12 @@ import { markInputRegex, extractMarkAttributesFromMatch } from '../services/mark export default Superscript.extend({ addInputRules() { - return [markInputRule(markInputRegex('sup'), this.type, extractMarkAttributesFromMatch)]; + return [ + markInputRule({ + find: markInputRegex('sup'), + type: this.type, + getAttributes: extractMarkAttributesFromMatch, + }), + ]; }, }); 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/extensions/table_of_contents.js b/app/assets/javascripts/content_editor/extensions/table_of_contents.js index 9e31158837e..a8882f9ede4 100644 --- a/app/assets/javascripts/content_editor/extensions/table_of_contents.js +++ b/app/assets/javascripts/content_editor/extensions/table_of_contents.js @@ -1,10 +1,7 @@ -import { Node } from '@tiptap/core'; -import { InputRule } from 'prosemirror-inputrules'; +import { Node, InputRule } from '@tiptap/core'; import { s__ } from '~/locale'; import { PARSE_HTML_PRIORITY_HIGHEST } from '../constants'; -export const inputRuleRegExps = [/^\[\[_TOC_\]\]$/, /^\[TOC\]$/]; - export default Node.create({ name: 'tableOfContents', @@ -34,17 +31,21 @@ export default Node.create({ addInputRules() { const { type } = this; + const inputRuleRegExps = [/^\[\[_TOC_\]\]$/, /^\[TOC\]$/]; return inputRuleRegExps.map( (regex) => - new InputRule(regex, (state, match, start, end) => { - const { tr } = state; + new InputRule({ + find: regex, + handler: ({ state, range: { from, to }, match }) => { + const { tr } = state; - if (match) { - tr.replaceWith(start - 1, end, type.create()); - } + if (match) { + tr.replaceWith(from - 1, to, type.create()); + } - return tr; + return tr; + }, }), ); }, diff --git a/app/assets/javascripts/content_editor/extensions/word_break.js b/app/assets/javascripts/content_editor/extensions/word_break.js index 93b42466850..fa7e02f8cc8 100644 --- a/app/assets/javascripts/content_editor/extensions/word_break.js +++ b/app/assets/javascripts/content_editor/extensions/word_break.js @@ -1,7 +1,5 @@ import { Node, mergeAttributes, nodeInputRule } from '@tiptap/core'; -export const inputRegex = /^<wbr>$/; - export default Node.create({ name: 'wordBreak', inline: true, @@ -24,6 +22,8 @@ export default Node.create({ }, addInputRules() { - return [nodeInputRule(inputRegex, this.type)]; + const inputRegex = /^<wbr>$/; + + return [nodeInputRule({ find: inputRegex, type: this.type })]; }, }); 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/track_input_rules_and_shortcuts.js b/app/assets/javascripts/content_editor/services/track_input_rules_and_shortcuts.js index d26f32a7e7a..9b1cb76f845 100644 --- a/app/assets/javascripts/content_editor/services/track_input_rules_and_shortcuts.js +++ b/app/assets/javascripts/content_editor/services/track_input_rules_and_shortcuts.js @@ -1,5 +1,5 @@ import { mapValues } from 'lodash'; -import { InputRule } from 'prosemirror-inputrules'; +import { InputRule } from '@tiptap/core'; import { ENTER_KEY, BACKSPACE_KEY } from '~/lib/utils/keys'; import Tracking from '~/tracking'; import { @@ -17,17 +17,20 @@ const trackKeyboardShortcut = (contentType, commandFn, shortcut) => () => { }; const trackInputRule = (contentType, inputRule) => { - return new InputRule(inputRule.match, (...args) => { - const result = inputRule.handler(...args); + return new InputRule({ + find: inputRule.find, + handler: (...args) => { + const result = inputRule.handler(...args); - if (result) { - Tracking.event(undefined, INPUT_RULE_TRACKING_ACTION, { - label: CONTENT_EDITOR_TRACKING_LABEL, - property: contentType, - }); - } + if (result !== null) { + Tracking.event(undefined, INPUT_RULE_TRACKING_ACTION, { + label: CONTENT_EDITOR_TRACKING_LABEL, + property: contentType, + }); + } - return result; + return result; + }, }); }; 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', }); } }; |