diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-11-18 13:16:36 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-11-18 13:16:36 +0000 |
commit | 311b0269b4eb9839fa63f80c8d7a58f32b8138a0 (patch) | |
tree | 07e7870bca8aed6d61fdcc810731c50d2c40af47 /app/assets/javascripts/content_editor/extensions | |
parent | 27909cef6c4170ed9205afa7426b8d3de47cbb0c (diff) | |
download | gitlab-ce-056d9df33865790d1b3c10f77912e00f61193000.tar.gz |
Add latest changes from gitlab-org/gitlab@14-5-stable-eev14.5.0-rc42
Diffstat (limited to 'app/assets/javascripts/content_editor/extensions')
17 files changed, 149 insertions, 68 deletions
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 })]; }, }); |