summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/behaviors/markdown
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-03-18 20:02:30 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2022-03-18 20:02:30 +0000
commit41fe97390ceddf945f3d967b8fdb3de4c66b7dea (patch)
tree9c8d89a8624828992f06d892cd2f43818ff5dcc8 /app/assets/javascripts/behaviors/markdown
parent0804d2dc31052fb45a1efecedc8e06ce9bc32862 (diff)
downloadgitlab-ce-41fe97390ceddf945f3d967b8fdb3de4c66b7dea.tar.gz
Add latest changes from gitlab-org/gitlab@14-9-stable-eev14.9.0-rc42
Diffstat (limited to 'app/assets/javascripts/behaviors/markdown')
-rw-r--r--app/assets/javascripts/behaviors/markdown/editor_extensions.js78
-rw-r--r--app/assets/javascripts/behaviors/markdown/marks/bold.js22
-rw-r--r--app/assets/javascripts/behaviors/markdown/marks/code.js17
-rw-r--r--app/assets/javascripts/behaviors/markdown/marks/inline_diff.js66
-rw-r--r--app/assets/javascripts/behaviors/markdown/marks/inline_html.js71
-rw-r--r--app/assets/javascripts/behaviors/markdown/marks/italic.js16
-rw-r--r--app/assets/javascripts/behaviors/markdown/marks/link.js58
-rw-r--r--app/assets/javascripts/behaviors/markdown/marks/math.js61
-rw-r--r--app/assets/javascripts/behaviors/markdown/marks/strike.js31
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/audio.js9
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/blockquote.js18
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/bullet_list.js16
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/code_block.js127
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/description_details.js30
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/description_list.js29
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/description_term.js32
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/details.js30
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/doc.js21
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/emoji.js84
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/hard_break.js18
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/heading.js26
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/horizontal_rule.js15
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/image.js83
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/list_item.js17
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/ordered_list.js29
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/ordered_task_list.js38
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/paragraph.js29
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/playable.js93
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/reference.js85
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/summary.js32
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/table.js32
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/table_body.js30
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/table_cell.js54
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/table_head.js30
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/table_header_row.js40
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/table_of_contents.js49
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/table_row.js30
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/task_list.js39
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/task_list_item.js70
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/text.js23
-rw-r--r--app/assets/javascripts/behaviors/markdown/nodes/video.js10
-rw-r--r--app/assets/javascripts/behaviors/markdown/render_sandboxed_mermaid.js2
-rw-r--r--app/assets/javascripts/behaviors/markdown/schema.js32
-rw-r--r--app/assets/javascripts/behaviors/markdown/serializer.js32
44 files changed, 784 insertions, 970 deletions
diff --git a/app/assets/javascripts/behaviors/markdown/editor_extensions.js b/app/assets/javascripts/behaviors/markdown/editor_extensions.js
index b512e4dbc8b..165031c3e7d 100644
--- a/app/assets/javascripts/behaviors/markdown/editor_extensions.js
+++ b/app/assets/javascripts/behaviors/markdown/editor_extensions.js
@@ -48,54 +48,48 @@ import Video from './nodes/video';
// from GFM should have a node or mark here.
// The GFM-to-HTML-to-GFM cycle is tested in spec/features/markdown/copy_as_gfm_spec.rb.
-export default [
- new Doc(),
- new Paragraph(),
- new Text(),
+export default {
+ nodes: [
+ Doc(),
+ Paragraph(),
+ Text(),
- new Blockquote(),
- new CodeBlock(),
- new HardBreak(),
- new Heading({ maxLevel: 6 }),
- new HorizontalRule(),
- new Image(),
+ Blockquote(),
+ CodeBlock(),
+ HardBreak(),
+ Heading(),
+ HorizontalRule(),
+ Image(),
- new Table(),
- new TableHead(),
- new TableBody(),
- new TableHeaderRow(),
- new TableRow(),
- new TableCell(),
+ Table(),
+ TableHead(),
+ TableBody(),
+ TableHeaderRow(),
+ TableRow(),
+ TableCell(),
- new Emoji(),
- new Reference(),
+ Emoji(),
+ Reference(),
- new TableOfContents(),
- new Video(),
- new Audio(),
+ TableOfContents(),
+ Video(),
+ Audio(),
- new BulletList(),
- new OrderedList(),
- new ListItem(),
+ BulletList(),
+ OrderedList(),
+ ListItem(),
- new DescriptionList(),
- new DescriptionTerm(),
- new DescriptionDetails(),
+ DescriptionList(),
+ DescriptionTerm(),
+ DescriptionDetails(),
- new TaskList(),
- new OrderedTaskList(),
- new TaskListItem(),
+ TaskList(),
+ OrderedTaskList(),
+ TaskListItem(),
- new Summary(),
- new Details(),
+ Summary(),
+ Details(),
+ ],
- new Bold(),
- new Italic(),
- new Strike(),
- new InlineDiff(),
-
- new Link(),
- new Code(),
- new MathMark(),
- new InlineHTML(),
-];
+ marks: [Bold(), Italic(), Strike(), InlineDiff(), Link(), Code(), MathMark(), InlineHTML()],
+};
diff --git a/app/assets/javascripts/behaviors/markdown/marks/bold.js b/app/assets/javascripts/behaviors/markdown/marks/bold.js
index 89e373220af..dd730947a5f 100644
--- a/app/assets/javascripts/behaviors/markdown/marks/bold.js
+++ b/app/assets/javascripts/behaviors/markdown/marks/bold.js
@@ -1,11 +1,17 @@
-/* eslint-disable class-methods-use-this */
-
-import { Bold as BaseBold } from 'tiptap-extensions';
import { defaultMarkdownSerializer } from '~/lib/prosemirror_markdown_serializer';
// Transforms generated HTML back to GFM for Banzai::Filter::MarkdownFilter
-export default class Bold extends BaseBold {
- get toMarkdown() {
- return defaultMarkdownSerializer.marks.strong;
- }
-}
+export default () => {
+ return {
+ name: 'bold',
+ schema: {
+ parseDOM: [
+ {
+ tag: 'strong',
+ },
+ ],
+ toDOM: () => ['strong', 0],
+ },
+ toMarkdown: defaultMarkdownSerializer.marks.strong,
+ };
+};
diff --git a/app/assets/javascripts/behaviors/markdown/marks/code.js b/app/assets/javascripts/behaviors/markdown/marks/code.js
index 68368dec676..ea5af8b4a1f 100644
--- a/app/assets/javascripts/behaviors/markdown/marks/code.js
+++ b/app/assets/javascripts/behaviors/markdown/marks/code.js
@@ -1,11 +1,12 @@
-/* eslint-disable class-methods-use-this */
-
-import { Code as BaseCode } from 'tiptap-extensions';
import { defaultMarkdownSerializer } from '~/lib/prosemirror_markdown_serializer';
// Transforms generated HTML back to GFM for Banzai::Filter::MarkdownFilter
-export default class Code extends BaseCode {
- get toMarkdown() {
- return defaultMarkdownSerializer.marks.code;
- }
-}
+export default () => ({
+ name: 'code',
+ schema: {
+ excludes: '_',
+ parseDOM: [{ tag: 'code' }],
+ toDOM: () => ['code', 0],
+ },
+ toMarkdown: defaultMarkdownSerializer.marks.code,
+});
diff --git a/app/assets/javascripts/behaviors/markdown/marks/inline_diff.js b/app/assets/javascripts/behaviors/markdown/marks/inline_diff.js
index 7f1506cd5d9..69d345c81e4 100644
--- a/app/assets/javascripts/behaviors/markdown/marks/inline_diff.js
+++ b/app/assets/javascripts/behaviors/markdown/marks/inline_diff.js
@@ -1,41 +1,29 @@
-/* eslint-disable class-methods-use-this */
-
-import { Mark } from 'tiptap';
-
// Transforms generated HTML back to GFM for Banzai::Filter::InlineDiffFilter
-export default class InlineDiff extends Mark {
- get name() {
- return 'inline_diff';
- }
-
- get schema() {
- return {
- attrs: {
- addition: {
- default: true,
- },
+export default () => ({
+ name: 'inline_diff',
+ schema: {
+ attrs: {
+ addition: {
+ default: true,
},
- parseDOM: [
- { tag: 'span.idiff.addition', attrs: { addition: true } },
- { tag: 'span.idiff.deletion', attrs: { addition: false } },
- ],
- toDOM: (node) => [
- 'span',
- { class: `idiff left right ${node.attrs.addition ? 'addition' : 'deletion'}` },
- 0,
- ],
- };
- }
-
- get toMarkdown() {
- return {
- mixable: true,
- open(state, mark) {
- return mark.attrs.addition ? '{+' : '{-';
- },
- close(state, mark) {
- return mark.attrs.addition ? '+}' : '-}';
- },
- };
- }
-}
+ },
+ parseDOM: [
+ { tag: 'span.idiff.addition', attrs: { addition: true } },
+ { tag: 'span.idiff.deletion', attrs: { addition: false } },
+ ],
+ toDOM: (node) => [
+ 'span',
+ { class: `idiff left right ${node.attrs.addition ? 'addition' : 'deletion'}` },
+ 0,
+ ],
+ },
+ toMarkdown: {
+ mixable: true,
+ open(_, mark) {
+ return mark.attrs.addition ? '{+' : '{-';
+ },
+ close(_, mark) {
+ return mark.attrs.addition ? '+}' : '-}';
+ },
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/marks/inline_html.js b/app/assets/javascripts/behaviors/markdown/marks/inline_html.js
index e957f81b774..4520598e0ab 100644
--- a/app/assets/javascripts/behaviors/markdown/marks/inline_html.js
+++ b/app/assets/javascripts/behaviors/markdown/marks/inline_html.js
@@ -1,46 +1,35 @@
-/* eslint-disable class-methods-use-this */
-
import { escape } from 'lodash';
-import { Mark } from 'tiptap';
// Transforms generated HTML back to GFM for Banzai::Filter::MarkdownFilter
-export default class InlineHTML extends Mark {
- get name() {
- return 'inline_html';
- }
-
- get schema() {
- return {
- excludes: '',
- attrs: {
- tag: {},
- title: { default: null },
- },
- parseDOM: [
- {
- tag: 'sup, sub, kbd, q, samp, var',
- getAttrs: (el) => ({ tag: el.nodeName.toLowerCase() }),
- },
- {
- tag: 'abbr',
- getAttrs: (el) => ({ tag: 'abbr', title: el.getAttribute('title') }),
- },
- ],
- toDOM: (node) => [node.attrs.tag, { title: node.attrs.title }, 0],
- };
- }
-
- get toMarkdown() {
- return {
- mixable: true,
- open(state, mark) {
- return `<${mark.attrs.tag}${
- mark.attrs.title ? ` title="${state.esc(escape(mark.attrs.title))}"` : ''
- }>`;
+export default () => ({
+ name: 'inline_html',
+ schema: {
+ excludes: '',
+ attrs: {
+ tag: {},
+ title: { default: null },
+ },
+ parseDOM: [
+ {
+ tag: 'sup, sub, kbd, q, samp, var',
+ getAttrs: (el) => ({ tag: el.nodeName.toLowerCase() }),
},
- close(state, mark) {
- return `</${mark.attrs.tag}>`;
+ {
+ tag: 'abbr',
+ getAttrs: (el) => ({ tag: 'abbr', title: el.getAttribute('title') }),
},
- };
- }
-}
+ ],
+ toDOM: (node) => [node.attrs.tag, { title: node.attrs.title }, 0],
+ },
+ toMarkdown: {
+ mixable: true,
+ open(state, mark) {
+ return `<${mark.attrs.tag}${
+ mark.attrs.title ? ` title="${state.esc(escape(mark.attrs.title))}"` : ''
+ }>`;
+ },
+ close(_, mark) {
+ return `</${mark.attrs.tag}>`;
+ },
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/marks/italic.js b/app/assets/javascripts/behaviors/markdown/marks/italic.js
index 7dc86102f18..3ec8f0071e9 100644
--- a/app/assets/javascripts/behaviors/markdown/marks/italic.js
+++ b/app/assets/javascripts/behaviors/markdown/marks/italic.js
@@ -1,11 +1,11 @@
-/* eslint-disable class-methods-use-this */
-
-import { Italic as BaseItalic } from 'tiptap-extensions';
import { defaultMarkdownSerializer } from '~/lib/prosemirror_markdown_serializer';
// Transforms generated HTML back to GFM for Banzai::Filter::MarkdownFilter
-export default class Italic extends BaseItalic {
- get toMarkdown() {
- return defaultMarkdownSerializer.marks.em;
- }
-}
+export default () => ({
+ name: 'italic',
+ schema: {
+ parseDOM: [{ tag: 'em' }],
+ toDOM: () => ['em', 0],
+ },
+ toMarkdown: defaultMarkdownSerializer.marks.em,
+});
diff --git a/app/assets/javascripts/behaviors/markdown/marks/link.js b/app/assets/javascripts/behaviors/markdown/marks/link.js
index b5e09017d83..977453fee01 100644
--- a/app/assets/javascripts/behaviors/markdown/marks/link.js
+++ b/app/assets/javascripts/behaviors/markdown/marks/link.js
@@ -1,21 +1,47 @@
-/* eslint-disable class-methods-use-this */
-
-import { Link as BaseLink } from 'tiptap-extensions';
import { defaultMarkdownSerializer } from '~/lib/prosemirror_markdown_serializer';
// Transforms generated HTML back to GFM for Banzai::Filter::MarkdownFilter
-export default class Link extends BaseLink {
- get toMarkdown() {
- return {
- mixable: true,
- open(state, mark, parent, index) {
- const open = defaultMarkdownSerializer.marks.link.open(state, mark, parent, index);
- return open === '<' ? '' : open;
+export default () => ({
+ name: 'link',
+ schema: {
+ attrs: {
+ href: {
+ default: null,
+ },
+ target: {
+ default: null,
+ },
+ },
+ inclusive: false,
+ parseDOM: [
+ {
+ tag: 'a[href]',
+ getAttrs: (dom) => ({
+ href: dom.getAttribute('href'),
+ target: dom.getAttribute('target'),
+ }),
},
- close(state, mark, parent, index) {
- const close = defaultMarkdownSerializer.marks.link.close(state, mark, parent, index);
- return close === '>' ? '' : close;
+ ],
+ toDOM: (node) => [
+ 'a',
+ {
+ ...node.attrs,
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ rel: 'noopener noreferrer nofollow',
+ target: node.attrs.target,
},
- };
- }
-}
+ 0,
+ ],
+ },
+ toMarkdown: {
+ mixable: true,
+ open(state, mark, parent, index) {
+ const open = defaultMarkdownSerializer.marks.link.open(state, mark, parent, index);
+ return open === '<' ? '' : open;
+ },
+ close(state, mark, parent, index) {
+ const close = defaultMarkdownSerializer.marks.link.close(state, mark, parent, index);
+ return close === '>' ? '' : close;
+ },
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/marks/math.js b/app/assets/javascripts/behaviors/markdown/marks/math.js
index ca25ff7d07d..a50a649b6eb 100644
--- a/app/assets/javascripts/behaviors/markdown/marks/math.js
+++ b/app/assets/javascripts/behaviors/markdown/marks/math.js
@@ -1,42 +1,31 @@
-/* eslint-disable class-methods-use-this */
-
-import { Mark } from 'tiptap';
import { defaultMarkdownSerializer } from '~/lib/prosemirror_markdown_serializer';
import { HIGHER_PARSE_RULE_PRIORITY } from '../constants';
// Transforms generated HTML back to GFM for Banzai::Filter::MathFilter
-export default class MathMark extends Mark {
- get name() {
- return 'math';
- }
-
- get schema() {
- return {
- parseDOM: [
- // Matches HTML generated by Banzai::Filter::MathFilter
- {
- tag: 'code.code.math[data-math-style=inline]',
- priority: HIGHER_PARSE_RULE_PRIORITY,
- },
- // Matches HTML after being transformed by app/assets/javascripts/behaviors/markdown/render_math.js
- {
- tag: 'span.katex',
- contentElement: 'annotation[encoding="application/x-tex"]',
- },
- ],
- toDOM: () => ['code', { class: 'code math', 'data-math-style': 'inline' }, 0],
- };
- }
-
- get toMarkdown() {
- return {
- escape: false,
- open(state, mark, parent, index) {
- return `$${defaultMarkdownSerializer.marks.code.open(state, mark, parent, index)}`;
+export default () => ({
+ name: 'math',
+ schema: {
+ parseDOM: [
+ // Matches HTML generated by Banzai::Filter::MathFilter
+ {
+ tag: 'code.code.math[data-math-style=inline]',
+ priority: HIGHER_PARSE_RULE_PRIORITY,
},
- close(state, mark, parent, index) {
- return `${defaultMarkdownSerializer.marks.code.close(state, mark, parent, index)}$`;
+ // Matches HTML after being transformed by app/assets/javascripts/behaviors/markdown/render_math.js
+ {
+ tag: 'span.katex',
+ contentElement: 'annotation[encoding="application/x-tex"]',
},
- };
- }
-}
+ ],
+ toDOM: () => ['code', { class: 'code math', 'data-math-style': 'inline' }, 0],
+ },
+ toMarkdown: {
+ escape: false,
+ open(state, mark, parent, index) {
+ return `$${defaultMarkdownSerializer.marks.code.open(state, mark, parent, index)}`;
+ },
+ close(state, mark, parent, index) {
+ return `${defaultMarkdownSerializer.marks.code.close(state, mark, parent, index)}$`;
+ },
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/marks/strike.js b/app/assets/javascripts/behaviors/markdown/marks/strike.js
index c2951a40a4b..967c0a120cd 100644
--- a/app/assets/javascripts/behaviors/markdown/marks/strike.js
+++ b/app/assets/javascripts/behaviors/markdown/marks/strike.js
@@ -1,15 +1,18 @@
-/* eslint-disable class-methods-use-this */
-
-import { Strike as BaseStrike } from 'tiptap-extensions';
-
// Transforms generated HTML back to GFM for Banzai::Filter::MarkdownFilter
-export default class Strike extends BaseStrike {
- get toMarkdown() {
- return {
- open: '~~',
- close: '~~',
- mixable: true,
- expelEnclosingWhitespace: true,
- };
- }
-}
+export default () => ({
+ name: 'strike',
+ schema: {
+ parseDOM: [
+ {
+ tag: 'del',
+ },
+ ],
+ toDOM: () => ['s', 0],
+ },
+ toMarkdown: {
+ open: '~~',
+ close: '~~',
+ mixable: true,
+ expelEnclosingWhitespace: true,
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/audio.js b/app/assets/javascripts/behaviors/markdown/nodes/audio.js
index 146349b118c..97ab86c6d23 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/audio.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/audio.js
@@ -1,9 +1,4 @@
-import Playable from './playable';
+import playable from './playable';
// Transforms generated HTML back to GFM for Banzai::Filter::AudioLinkFilter
-export default class Audio extends Playable {
- constructor() {
- super();
- this.mediaType = 'audio';
- }
-}
+export default () => playable({ mediaType: 'audio' });
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/blockquote.js b/app/assets/javascripts/behaviors/markdown/nodes/blockquote.js
index 8b14a04e2fe..6a4552d47e4 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/blockquote.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/blockquote.js
@@ -1,13 +1,19 @@
-/* eslint-disable class-methods-use-this */
-
-import { Blockquote as BaseBlockquote } from 'tiptap-extensions';
import { defaultMarkdownSerializer } from '~/lib/prosemirror_markdown_serializer';
// Transforms generated HTML back to GFM for Banzai::Filter::MarkdownFilter
-export default class Blockquote extends BaseBlockquote {
+export default () => ({
+ name: 'blockquote',
+ schema: {
+ content: 'block*',
+ group: 'block',
+ defining: true,
+ draggable: false,
+ parseDOM: [{ tag: 'blockquote' }],
+ toDOM: () => ['blockquote', 0],
+ },
toMarkdown(state, node) {
if (!node.childCount) return;
defaultMarkdownSerializer.nodes.blockquote(state, node);
- }
-}
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/bullet_list.js b/app/assets/javascripts/behaviors/markdown/nodes/bullet_list.js
index ef1eafaa419..95cd3605da5 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/bullet_list.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/bullet_list.js
@@ -1,11 +1,15 @@
-/* eslint-disable class-methods-use-this */
-
-import { BulletList as BaseBulletList } from 'tiptap-extensions';
import { defaultMarkdownSerializer } from '~/lib/prosemirror_markdown_serializer';
// Transforms generated HTML back to GFM for Banzai::Filter::MarkdownFilter
-export default class BulletList extends BaseBulletList {
+export default () => ({
+ name: 'bullet_list',
+ schema: {
+ content: 'list_item+',
+ group: 'block',
+ parseDOM: [{ tag: 'ul' }],
+ toDOM: () => ['ul', 0],
+ },
toMarkdown(state, node) {
defaultMarkdownSerializer.nodes.bullet_list(state, node);
- }
-}
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/code_block.js b/app/assets/javascripts/behaviors/markdown/nodes/code_block.js
index cd90d67c60d..0ff59779e7d 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/code_block.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/code_block.js
@@ -1,7 +1,3 @@
-/* eslint-disable class-methods-use-this */
-
-import { CodeBlock as BaseCodeBlock } from 'tiptap-extensions';
-
const PLAINTEXT_LANG = 'plaintext';
// Transforms generated HTML back to GFM for:
@@ -9,68 +5,67 @@ const PLAINTEXT_LANG = 'plaintext';
// - Banzai::Filter::MathFilter
// - Banzai::Filter::MermaidFilter
// - Banzai::Filter::SuggestionFilter
-export default class CodeBlock extends BaseCodeBlock {
- get schema() {
- return {
- content: 'text*',
- marks: '',
- group: 'block',
- code: true,
- defining: true,
- attrs: {
- lang: { default: PLAINTEXT_LANG },
- },
- parseDOM: [
- // Matches HTML generated by Banzai::Filter::SyntaxHighlightFilter, Banzai::Filter::MathFilter, Banzai::Filter::MermaidFilter, or Banzai::Filter::SuggestionFilter
- {
- tag: 'pre.code.highlight',
- preserveWhitespace: 'full',
- getAttrs: (el) => {
- const lang = el.getAttribute('lang');
- if (!lang || lang === '') return {};
+export default () => ({
+ name: 'code_block',
+ schema: {
+ content: 'text*',
+ marks: '',
+ group: 'block',
+ code: true,
+ defining: true,
+ attrs: {
+ lang: { default: PLAINTEXT_LANG },
+ },
+ parseDOM: [
+ // Matches HTML generated by Banzai::Filter::SyntaxHighlightFilter, Banzai::Filter::MathFilter, Banzai::Filter::MermaidFilter, or Banzai::Filter::SuggestionFilter
+ {
+ tag: 'pre.code.highlight',
+ preserveWhitespace: 'full',
+ getAttrs: (el) => {
+ const lang = el.getAttribute('lang');
+ if (!lang || lang === '') return {};
- return { lang };
- },
- },
- // Matches HTML generated by Banzai::Filter::MathFilter,
- // after being transformed by app/assets/javascripts/behaviors/markdown/render_math.js
- {
- tag: 'span.katex-display',
- preserveWhitespace: 'full',
- contentElement: 'annotation[encoding="application/x-tex"]',
- attrs: { lang: 'math' },
- },
- // Matches HTML generated by Banzai::Filter::MermaidFilter,
- // after being transformed by app/assets/javascripts/behaviors/markdown/render_mermaid.js
- {
- tag: 'svg.mermaid',
- preserveWhitespace: 'full',
- contentElement: 'text.source',
- attrs: { lang: 'mermaid' },
- },
- // Matches HTML generated by Banzai::Filter::SuggestionFilter,
- // after being transformed by app/assets/javascripts/vue_shared/components/markdown/suggestions.vue
- {
- tag: '.md-suggestion',
- skip: true,
- },
- {
- tag: '.md-suggestion-header',
- ignore: true,
+ return { lang };
},
- {
- tag: '.md-suggestion-diff',
- preserveWhitespace: 'full',
- getContent: (el, schema) =>
- [...el.querySelectorAll('.line_content.new span')].map((span) =>
- schema.text(span.innerText),
- ),
- attrs: { lang: 'suggestion' },
- },
- ],
- toDOM: (node) => ['pre', { class: 'code highlight', lang: node.attrs.lang }, ['code', 0]],
- };
- }
+ },
+ // Matches HTML generated by Banzai::Filter::MathFilter,
+ // after being transformed by app/assets/javascripts/behaviors/markdown/render_math.js
+ {
+ tag: 'span.katex-display',
+ preserveWhitespace: 'full',
+ contentElement: 'annotation[encoding="application/x-tex"]',
+ attrs: { lang: 'math' },
+ },
+ // Matches HTML generated by Banzai::Filter::MermaidFilter,
+ // after being transformed by app/assets/javascripts/behaviors/markdown/render_mermaid.js
+ {
+ tag: 'svg.mermaid',
+ preserveWhitespace: 'full',
+ contentElement: 'text.source',
+ attrs: { lang: 'mermaid' },
+ },
+ // Matches HTML generated by Banzai::Filter::SuggestionFilter,
+ // after being transformed by app/assets/javascripts/vue_shared/components/markdown/suggestions.vue
+ {
+ tag: '.md-suggestion',
+ skip: true,
+ },
+ {
+ tag: '.md-suggestion-header',
+ ignore: true,
+ },
+ {
+ tag: '.md-suggestion-diff',
+ preserveWhitespace: 'full',
+ getContent: (el, schema) =>
+ [...el.querySelectorAll('.line_content.new span')].map((span) =>
+ schema.text(span.innerText),
+ ),
+ attrs: { lang: 'suggestion' },
+ },
+ ],
+ toDOM: (node) => ['pre', { class: 'code highlight', lang: node.attrs.lang }, ['code', 0]],
+ },
toMarkdown(state, node) {
if (!node.childCount) return;
@@ -95,5 +90,5 @@ export default class CodeBlock extends BaseCodeBlock {
state.write('```');
state.closeBlock(node);
- }
-}
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/description_details.js b/app/assets/javascripts/behaviors/markdown/nodes/description_details.js
index a4451d8ce8d..20760286045 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/description_details.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/description_details.js
@@ -1,22 +1,14 @@
-/* eslint-disable class-methods-use-this */
-
-import { Node } from 'tiptap';
-
// Transforms generated HTML back to GFM for Banzai::Filter::MarkdownFilter
-export default class DescriptionDetails extends Node {
- get name() {
- return 'description_details';
- }
+export default () => ({
+ name: 'description_details',
- get schema() {
- return {
- content: 'text*',
- marks: '',
- defining: true,
- parseDOM: [{ tag: 'dd' }],
- toDOM: () => ['dd', 0],
- };
- }
+ schema: {
+ content: 'text*',
+ marks: '',
+ defining: true,
+ parseDOM: [{ tag: 'dd' }],
+ toDOM: () => ['dd', 0],
+ },
toMarkdown(state, node) {
state.flushClose(1);
@@ -24,5 +16,5 @@ export default class DescriptionDetails extends Node {
state.text(node.textContent, false);
state.write('</dd>');
state.closeBlock(node);
- }
-}
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/description_list.js b/app/assets/javascripts/behaviors/markdown/nodes/description_list.js
index 6aa1aca29d7..c5305c48423 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/description_list.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/description_list.js
@@ -1,21 +1,12 @@
-/* eslint-disable class-methods-use-this */
-
-import { Node } from 'tiptap';
-
// Transforms generated HTML back to GFM for Banzai::Filter::MarkdownFilter
-export default class DescriptionList extends Node {
- get name() {
- return 'description_list';
- }
-
- get schema() {
- return {
- content: '(description_term+ description_details+)+',
- group: 'block',
- parseDOM: [{ tag: 'dl' }],
- toDOM: () => ['dl', 0],
- };
- }
+export default () => ({
+ name: 'description_list',
+ schema: {
+ content: '(description_term+ description_details+)+',
+ group: 'block',
+ parseDOM: [{ tag: 'dl' }],
+ toDOM: () => ['dl', 0],
+ },
toMarkdown(state, node) {
state.write('<dl>\n');
@@ -24,5 +15,5 @@ export default class DescriptionList extends Node {
state.ensureNewLine();
state.write('</dl>');
state.closeBlock(node);
- }
-}
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/description_term.js b/app/assets/javascripts/behaviors/markdown/nodes/description_term.js
index 89057ec6444..f78f7f13fc4 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/description_term.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/description_term.js
@@ -1,28 +1,18 @@
-/* eslint-disable class-methods-use-this */
-
-import { Node } from 'tiptap';
-
// Transforms generated HTML back to GFM for Banzai::Filter::MarkdownFilter
-export default class DescriptionTerm extends Node {
- get name() {
- return 'description_term';
- }
-
- get schema() {
- return {
- content: 'text*',
- marks: '',
- defining: true,
- parseDOM: [{ tag: 'dt' }],
- toDOM: () => ['dt', 0],
- };
- }
-
+export default () => ({
+ name: 'description_term',
+ schema: {
+ content: 'text*',
+ marks: '',
+ defining: true,
+ parseDOM: [{ tag: 'dt' }],
+ toDOM: () => ['dt', 0],
+ },
toMarkdown(state, node) {
state.flushClose(state.closed && state.closed.type === node.type ? 1 : 2);
state.write('<dt>');
state.text(node.textContent, false);
state.write('</dt>');
state.closeBlock(node);
- }
-}
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/details.js b/app/assets/javascripts/behaviors/markdown/nodes/details.js
index 1c40dbb8168..9fb0d60b93a 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/details.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/details.js
@@ -1,22 +1,12 @@
-/* eslint-disable class-methods-use-this */
-
-import { Node } from 'tiptap';
-
// Transforms generated HTML back to GFM for Banzai::Filter::MarkdownFilter
-export default class Details extends Node {
- get name() {
- return 'details';
- }
-
- get schema() {
- return {
- content: 'summary block*',
- group: 'block',
- parseDOM: [{ tag: 'details' }],
- toDOM: () => ['details', { open: true, onclick: 'return false', tabindex: '-1' }, 0],
- };
- }
-
+export default () => ({
+ name: 'details',
+ schema: {
+ content: 'summary block*',
+ group: 'block',
+ parseDOM: [{ tag: 'details' }],
+ toDOM: () => ['details', { open: true, onclick: 'return false', tabindex: '-1' }, 0],
+ },
toMarkdown(state, node) {
state.write('<details>\n');
state.renderContent(node);
@@ -24,5 +14,5 @@ export default class Details extends Node {
state.ensureNewLine();
state.write('</details>');
state.closeBlock(node);
- }
-}
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/doc.js b/app/assets/javascripts/behaviors/markdown/nodes/doc.js
index 88b16fd85da..3101e6e0e3a 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/doc.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/doc.js
@@ -1,15 +1,6 @@
-/* eslint-disable class-methods-use-this */
-
-import { Node } from 'tiptap';
-
-export default class Doc extends Node {
- get name() {
- return 'doc';
- }
-
- get schema() {
- return {
- content: 'block+',
- };
- }
-}
+export default () => ({
+ name: 'doc',
+ schema: {
+ content: 'block+',
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/emoji.js b/app/assets/javascripts/behaviors/markdown/nodes/emoji.js
index 9d0890aa1b4..086c277bad4 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/emoji.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/emoji.js
@@ -1,53 +1,43 @@
-/* eslint-disable class-methods-use-this */
-
-import { Node } from 'tiptap';
-
// Transforms generated HTML back to GFM for Banzai::Filter::EmojiFilter
-export default class Emoji extends Node {
- get name() {
- return 'emoji';
- }
-
- get schema() {
- return {
- inline: true,
- group: 'inline',
- attrs: {
- name: {},
- title: {},
- moji: {},
+export default () => ({
+ name: 'emoji',
+ schema: {
+ inline: true,
+ group: 'inline',
+ attrs: {
+ name: {},
+ title: {},
+ moji: {},
+ },
+ parseDOM: [
+ {
+ tag: 'gl-emoji',
+ getAttrs: (el) => ({
+ name: el.dataset.name,
+ title: el.getAttribute('title'),
+ moji: el.textContent,
+ }),
},
- parseDOM: [
- {
- tag: 'gl-emoji',
- getAttrs: (el) => ({
- name: el.dataset.name,
- title: el.getAttribute('title'),
- moji: el.textContent,
- }),
- },
- {
- tag: 'img.emoji',
- getAttrs: (el) => {
- const name = el.getAttribute('title').replace(/^:|:$/g, '');
+ {
+ tag: 'img.emoji',
+ getAttrs: (el) => {
+ const name = el.getAttribute('title').replace(/^:|:$/g, '');
- return {
- name,
- title: name,
- moji: name,
- };
- },
+ return {
+ name,
+ title: name,
+ moji: name,
+ };
},
- ],
- toDOM: (node) => [
- 'gl-emoji',
- { 'data-name': node.attrs.name, title: node.attrs.title },
- node.attrs.moji,
- ],
- };
- }
-
+ },
+ ],
+ toDOM: (node) => [
+ 'gl-emoji',
+ { 'data-name': node.attrs.name, title: node.attrs.title },
+ node.attrs.moji,
+ ],
+ },
toMarkdown(state, node) {
state.write(`:${node.attrs.name}:`);
- }
-}
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/hard_break.js b/app/assets/javascripts/behaviors/markdown/nodes/hard_break.js
index 59e5d8ab3e2..1668af9c3f4 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/hard_break.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/hard_break.js
@@ -1,10 +1,14 @@
-/* eslint-disable class-methods-use-this */
-
-import { HardBreak as BaseHardBreak } from 'tiptap-extensions';
-
// Transforms generated HTML back to GFM for Banzai::Filter::MarkdownFilter
-export default class HardBreak extends BaseHardBreak {
+export default () => ({
+ name: 'hard_break',
+ schema: {
+ inline: true,
+ group: 'inline',
+ selectable: false,
+ parseDOM: [{ tag: 'br' }],
+ toDOM: () => ['br'],
+ },
toMarkdown(state) {
if (!state.atBlank()) state.write(' \n');
- }
-}
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/heading.js b/app/assets/javascripts/behaviors/markdown/nodes/heading.js
index 29967e61ffa..21b4ec69b70 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/heading.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/heading.js
@@ -1,13 +1,27 @@
-/* eslint-disable class-methods-use-this */
-
-import { Heading as BaseHeading } from 'tiptap-extensions';
import { defaultMarkdownSerializer } from '~/lib/prosemirror_markdown_serializer';
// Transforms generated HTML back to GFM for Banzai::Filter::MarkdownFilter
-export default class Heading extends BaseHeading {
+export default ({ levels = [1, 2, 3, 4, 5, 6] } = {}) => ({
+ name: 'heading',
+ schema: {
+ attrs: {
+ level: {
+ default: 1,
+ },
+ },
+ content: 'inline*',
+ group: 'block',
+ defining: true,
+ draggable: false,
+ parseDOM: levels.map((level) => ({
+ tag: `h${level}`,
+ attrs: { level },
+ })),
+ toDOM: (node) => [`h${node.attrs.level}`, 0],
+ },
toMarkdown(state, node) {
if (!node.childCount) return;
defaultMarkdownSerializer.nodes.heading(state, node);
- }
-}
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/horizontal_rule.js b/app/assets/javascripts/behaviors/markdown/nodes/horizontal_rule.js
index ee3aa145dc3..2d7074e567f 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/horizontal_rule.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/horizontal_rule.js
@@ -1,11 +1,14 @@
-/* eslint-disable class-methods-use-this */
-
-import { HorizontalRule as BaseHorizontalRule } from 'tiptap-extensions';
import { defaultMarkdownSerializer } from '~/lib/prosemirror_markdown_serializer';
// Transforms generated HTML back to GFM for Banzai::Filter::MarkdownFilter
-export default class HorizontalRule extends BaseHorizontalRule {
+export default () => ({
+ name: 'horizontal_rule',
+ schema: {
+ group: 'block',
+ parseDOM: [{ tag: 'hr' }],
+ toDOM: () => ['hr'],
+ },
toMarkdown(state, node) {
defaultMarkdownSerializer.nodes.horizontal_rule(state, node);
- }
-}
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/image.js b/app/assets/javascripts/behaviors/markdown/nodes/image.js
index 16647d2f96e..370cc347a05 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/image.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/image.js
@@ -1,53 +1,48 @@
-/* eslint-disable class-methods-use-this */
-
-import { Image as BaseImage } from 'tiptap-extensions';
import { placeholderImage } from '~/lazy_loader';
import { defaultMarkdownSerializer } from '~/lib/prosemirror_markdown_serializer';
import { HIGHER_PARSE_RULE_PRIORITY } from '../constants';
-export default class Image extends BaseImage {
- get schema() {
- return {
- attrs: {
- src: {},
- alt: {
- default: null,
- },
- title: {
- default: null,
- },
+export default () => ({
+ name: 'image',
+ schema: {
+ attrs: {
+ src: {},
+ alt: {
+ default: null,
},
- group: 'inline',
- inline: true,
- draggable: true,
- parseDOM: [
- // Matches HTML generated by Banzai::Filter::ImageLinkFilter
- {
- tag: 'a.no-attachment-icon',
- priority: HIGHER_PARSE_RULE_PRIORITY,
- skip: true,
- },
- // Matches HTML generated by Banzai::Filter::ImageLazyLoadFilter
- {
- tag: 'img[src]:not(.emoji)',
- getAttrs: (el) => {
- const imageSrc = el.src;
- const imageUrl =
- imageSrc && imageSrc !== placeholderImage ? imageSrc : el.dataset.src || '';
+ title: {
+ default: null,
+ },
+ },
+ group: 'inline',
+ inline: true,
+ draggable: true,
+ parseDOM: [
+ // Matches HTML generated by Banzai::Filter::ImageLinkFilter
+ {
+ tag: 'a.no-attachment-icon',
+ priority: HIGHER_PARSE_RULE_PRIORITY,
+ skip: true,
+ },
+ // Matches HTML generated by Banzai::Filter::ImageLazyLoadFilter
+ {
+ tag: 'img[src]:not(.emoji)',
+ getAttrs: (el) => {
+ const imageSrc = el.src;
+ const imageUrl =
+ imageSrc && imageSrc !== placeholderImage ? imageSrc : el.dataset.src || '';
- return {
- src: imageUrl,
- title: el.getAttribute('title'),
- alt: el.getAttribute('alt'),
- };
- },
+ return {
+ src: imageUrl,
+ title: el.getAttribute('title'),
+ alt: el.getAttribute('alt'),
+ };
},
- ],
- toDOM: (node) => ['img', node.attrs],
- };
- }
-
+ },
+ ],
+ toDOM: (node) => ['img', node.attrs],
+ },
toMarkdown(state, node) {
defaultMarkdownSerializer.nodes.image(state, node);
- }
-}
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/list_item.js b/app/assets/javascripts/behaviors/markdown/nodes/list_item.js
index 7204b7c09ba..97c1f07427d 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/list_item.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/list_item.js
@@ -1,11 +1,16 @@
-/* eslint-disable class-methods-use-this */
-
-import { ListItem as BaseListItem } from 'tiptap-extensions';
import { defaultMarkdownSerializer } from '~/lib/prosemirror_markdown_serializer';
// Transforms generated HTML back to GFM for Banzai::Filter::MarkdownFilter
-export default class ListItem extends BaseListItem {
+export default () => ({
+ name: 'list_item',
+ schema: {
+ content: 'paragraph block*',
+ defining: true,
+ draggable: false,
+ parseDOM: [{ tag: 'li' }],
+ toDOM: () => ['li', 0],
+ },
toMarkdown(state, node) {
defaultMarkdownSerializer.nodes.list_item(state, node);
- }
-}
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/ordered_list.js b/app/assets/javascripts/behaviors/markdown/nodes/ordered_list.js
index 4c1542d14ea..f2f3eff266a 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/ordered_list.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/ordered_list.js
@@ -1,10 +1,25 @@
-/* eslint-disable class-methods-use-this */
-
-import { OrderedList as BaseOrderedList } from 'tiptap-extensions';
-
// Transforms generated HTML back to GFM for Banzai::Filter::MarkdownFilter
-export default class OrderedList extends BaseOrderedList {
+export default () => ({
+ name: 'ordered_list',
+ schema: {
+ attrs: {
+ order: {
+ default: 1,
+ },
+ },
+ content: 'list_item+',
+ group: 'block',
+ parseDOM: [
+ {
+ tag: 'ol',
+ getAttrs: (dom) => ({
+ order: dom.hasAttribute('start') ? dom.getAttribute('start') + 1 : 1,
+ }),
+ },
+ ],
+ toDOM: (node) => (node.attrs.order === 1 ? ['ol', 0] : ['ol', { start: node.attrs.order }, 0]),
+ },
toMarkdown(state, node) {
state.renderList(node, ' ', () => '1. ');
- }
-}
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/ordered_task_list.js b/app/assets/javascripts/behaviors/markdown/nodes/ordered_task_list.js
index a28d7be3758..53a6a0d9e07 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/ordered_task_list.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/ordered_task_list.js
@@ -1,29 +1,21 @@
-/* eslint-disable class-methods-use-this */
-
-import { Node } from 'tiptap';
import { HIGHER_PARSE_RULE_PRIORITY } from '../constants';
// Transforms generated HTML back to GFM for Banzai::Filter::TaskListFilter
-export default class OrderedTaskList extends Node {
- get name() {
- return 'ordered_task_list';
- }
-
- get schema() {
- return {
- group: 'block',
- content: '(task_list_item|list_item)+',
- parseDOM: [
- {
- priority: HIGHER_PARSE_RULE_PRIORITY,
- tag: 'ol.task-list',
- },
- ],
- toDOM: () => ['ol', { class: 'task-list' }, 0],
- };
- }
+export default () => ({
+ name: 'ordered_task_list',
+ schema: {
+ group: 'block',
+ content: '(task_list_item|list_item)+',
+ parseDOM: [
+ {
+ priority: HIGHER_PARSE_RULE_PRIORITY,
+ tag: 'ol.task-list',
+ },
+ ],
+ toDOM: () => ['ol', { class: 'task-list' }, 0],
+ },
toMarkdown(state, node) {
state.renderList(node, ' ', () => '1. ');
- }
-}
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/paragraph.js b/app/assets/javascripts/behaviors/markdown/nodes/paragraph.js
index 5fd098cd46f..310feebb390 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/paragraph.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/paragraph.js
@@ -1,24 +1,15 @@
-/* eslint-disable class-methods-use-this */
-
-import { Node } from 'tiptap';
import { defaultMarkdownSerializer } from '~/lib/prosemirror_markdown_serializer';
// Transforms generated HTML back to GFM for Banzai::Filter::MarkdownFilter
-export default class Paragraph extends Node {
- get name() {
- return 'paragraph';
- }
-
- get schema() {
- return {
- content: 'inline*',
- group: 'block',
- parseDOM: [{ tag: 'p' }],
- toDOM: () => ['p', 0],
- };
- }
-
+export default () => ({
+ name: 'paragraph',
+ schema: {
+ content: 'inline*',
+ group: 'block',
+ parseDOM: [{ tag: 'p' }],
+ toDOM: () => ['p', 0],
+ },
toMarkdown(state, node) {
defaultMarkdownSerializer.nodes.paragraph(state, node);
- }
-}
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/playable.js b/app/assets/javascripts/behaviors/markdown/nodes/playable.js
index 90cbaf9ef4c..7559c2a6a8a 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/playable.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/playable.js
@@ -1,7 +1,3 @@
-/* eslint-disable class-methods-use-this */
-/* eslint-disable @gitlab/require-i18n-strings */
-
-import { Node } from 'tiptap';
import { defaultMarkdownSerializer } from '~/lib/prosemirror_markdown_serializer';
/**
@@ -10,62 +6,51 @@ import { defaultMarkdownSerializer } from '~/lib/prosemirror_markdown_serializer
* the `mediaType` property in their constructors.
* @abstract
*/
-export default class Playable extends Node {
- constructor() {
- super();
- this.mediaType = '';
- this.extraElementAttrs = {};
- }
-
- get name() {
- return this.mediaType;
- }
-
- get schema() {
- const attrs = {
- src: {},
- alt: {
- default: null,
- },
- };
-
- const parseDOM = [
+export default ({ mediaType, extraElementAttrs = {} }) => {
+ const attrs = {
+ src: {},
+ alt: {
+ default: null,
+ },
+ };
+ const parseDOM = [
+ {
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ tag: `.${mediaType}-container`,
+ getAttrs: (el) => ({
+ src: el.querySelector(mediaType).src,
+ alt: el.querySelector(mediaType).dataset.title,
+ }),
+ },
+ ];
+ const toDOM = (node) => [
+ 'span',
+ { class: `media-container ${mediaType}-container` },
+ [
+ mediaType,
{
- tag: `.${this.mediaType}-container`,
- getAttrs: (el) => ({
- src: el.querySelector(this.mediaType).src,
- alt: el.querySelector(this.mediaType).dataset.title,
- }),
+ src: node.attrs.src,
+ controls: true,
+ 'data-setup': '{}',
+ 'data-title': node.attrs.alt,
+ ...extraElementAttrs,
},
- ];
-
- const toDOM = (node) => [
- 'span',
- { class: `media-container ${this.mediaType}-container` },
- [
- this.mediaType,
- {
- src: node.attrs.src,
- controls: true,
- 'data-setup': '{}',
- 'data-title': node.attrs.alt,
- ...this.extraElementAttrs,
- },
- ],
- ['a', { href: node.attrs.src }, node.attrs.alt],
- ];
+ ],
+ ['a', { href: node.attrs.src }, node.attrs.alt],
+ ];
- return {
+ return {
+ name: mediaType,
+ schema: {
attrs,
group: 'inline',
inline: true,
draggable: true,
parseDOM,
toDOM,
- };
- }
-
- toMarkdown(state, node) {
- defaultMarkdownSerializer.nodes.image(state, node);
- }
-}
+ },
+ toMarkdown(state, node) {
+ defaultMarkdownSerializer.nodes.image(state, node);
+ },
+ };
+};
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/reference.js b/app/assets/javascripts/behaviors/markdown/nodes/reference.js
index dd82ea58ea5..9ae6ab07004 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/reference.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/reference.js
@@ -1,53 +1,44 @@
-/* eslint-disable class-methods-use-this */
-
-import { Node } from 'tiptap';
import { HIGHER_PARSE_RULE_PRIORITY } from '../constants';
// Transforms generated HTML back to GFM for Banzai::Filter::ReferenceFilter and subclasses
-export default class Reference extends Node {
- get name() {
- return 'reference';
- }
-
- get schema() {
- return {
- inline: true,
- group: 'inline',
- atom: true,
- attrs: {
- className: {},
- referenceType: {},
- originalText: { default: null },
- href: {},
- text: {},
+export default () => ({
+ name: 'reference',
+ schema: {
+ inline: true,
+ group: 'inline',
+ atom: true,
+ attrs: {
+ className: {},
+ referenceType: {},
+ originalText: { default: null },
+ href: {},
+ text: {},
+ },
+ parseDOM: [
+ {
+ tag: 'a.gfm:not([data-link=true])',
+ priority: HIGHER_PARSE_RULE_PRIORITY,
+ getAttrs: (el) => ({
+ className: el.className,
+ referenceType: el.dataset.referenceType,
+ originalText: el.dataset.original,
+ href: el.getAttribute('href'),
+ text: el.textContent,
+ }),
},
- parseDOM: [
- {
- tag: 'a.gfm:not([data-link=true])',
- priority: HIGHER_PARSE_RULE_PRIORITY,
- getAttrs: (el) => ({
- className: el.className,
- referenceType: el.dataset.referenceType,
- originalText: el.dataset.original,
- href: el.getAttribute('href'),
- text: el.textContent,
- }),
- },
- ],
- toDOM: (node) => [
- 'a',
- {
- class: node.attrs.className,
- href: node.attrs.href,
- 'data-reference-type': node.attrs.referenceType,
- 'data-original': node.attrs.originalText,
- },
- node.attrs.text,
- ],
- };
- }
-
+ ],
+ toDOM: (node) => [
+ 'a',
+ {
+ class: node.attrs.className,
+ href: node.attrs.href,
+ 'data-reference-type': node.attrs.referenceType,
+ 'data-original': node.attrs.originalText,
+ },
+ node.attrs.text,
+ ],
+ },
toMarkdown(state, node) {
state.write(node.attrs.originalText || node.attrs.text);
- }
-}
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/summary.js b/app/assets/javascripts/behaviors/markdown/nodes/summary.js
index 2e36e316d71..eb91b3c981e 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/summary.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/summary.js
@@ -1,27 +1,17 @@
-/* eslint-disable class-methods-use-this */
-
-import { Node } from 'tiptap';
-
// Transforms generated HTML back to GFM for Banzai::Filter::MarkdownFilter
-export default class Summary extends Node {
- get name() {
- return 'summary';
- }
-
- get schema() {
- return {
- content: 'text*',
- marks: '',
- defining: true,
- parseDOM: [{ tag: 'summary' }],
- toDOM: () => ['summary', 0],
- };
- }
-
+export default () => ({
+ name: 'summary',
+ schema: {
+ content: 'text*',
+ marks: '',
+ defining: true,
+ parseDOM: [{ tag: 'summary' }],
+ toDOM: () => ['summary', 0],
+ },
toMarkdown(state, node) {
state.write('<summary>');
state.text(node.textContent, false);
state.write('</summary>');
state.closeBlock(node);
- }
-}
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/table.js b/app/assets/javascripts/behaviors/markdown/nodes/table.js
index a7fcb9227cd..c766f7f1fba 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/table.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/table.js
@@ -1,25 +1,15 @@
-/* eslint-disable class-methods-use-this */
-
-import { Node } from 'tiptap';
-
// Transforms generated HTML back to GFM for Banzai::Filter::MarkdownFilter
-export default class Table extends Node {
- get name() {
- return 'table';
- }
-
- get schema() {
- return {
- content: 'table_head table_body',
- group: 'block',
- isolating: true,
- parseDOM: [{ tag: 'table' }],
- toDOM: () => ['table', 0],
- };
- }
-
+export default () => ({
+ name: 'table',
+ schema: {
+ content: 'table_head table_body',
+ group: 'block',
+ isolating: true,
+ parseDOM: [{ tag: 'table' }],
+ toDOM: () => ['table', 0],
+ },
toMarkdown(state, node) {
state.renderContent(node);
state.closeBlock(node);
- }
-}
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/table_body.js b/app/assets/javascripts/behaviors/markdown/nodes/table_body.js
index 403556dc0c8..0a49fb558ae 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/table_body.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/table_body.js
@@ -1,24 +1,14 @@
-/* eslint-disable class-methods-use-this */
-
-import { Node } from 'tiptap';
-
// Transforms generated HTML back to GFM for Banzai::Filter::MarkdownFilter
-export default class TableBody extends Node {
- get name() {
- return 'table_body';
- }
-
- get schema() {
- return {
- content: 'table_row+',
- parseDOM: [{ tag: 'tbody' }],
- toDOM: () => ['tbody', 0],
- };
- }
-
- toMarkdown(state, node) {
+export default () => ({
+ name: 'table_body',
+ schema: {
+ content: 'table_row+',
+ parseDOM: [{ tag: 'tbody' }],
+ toDOM: () => ['tbody', 0],
+ },
+ toMarkdown: (state, node) => {
state.flushClose(1);
state.renderContent(node);
state.closeBlock(node);
- }
-}
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/table_cell.js b/app/assets/javascripts/behaviors/markdown/nodes/table_cell.js
index ebb66cd4da5..f46344ba43c 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/table_cell.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/table_cell.js
@@ -1,35 +1,25 @@
-/* eslint-disable class-methods-use-this */
-
-import { Node } from 'tiptap';
-
// Transforms generated HTML back to GFM for Banzai::Filter::MarkdownFilter
-export default class TableCell extends Node {
- get name() {
- return 'table_cell';
- }
-
- get schema() {
- return {
- attrs: {
- header: { default: false },
- align: { default: null },
+export default () => ({
+ name: 'table_cell',
+ schema: {
+ attrs: {
+ header: { default: false },
+ align: { default: null },
+ },
+ content: 'inline*',
+ isolating: true,
+ parseDOM: [
+ {
+ tag: 'td, th',
+ getAttrs: (el) => ({
+ header: el.tagName === 'TH',
+ align: el.getAttribute('align') || el.style.textAlign,
+ }),
},
- content: 'inline*',
- isolating: true,
- parseDOM: [
- {
- tag: 'td, th',
- getAttrs: (el) => ({
- header: el.tagName === 'TH',
- align: el.getAttribute('align') || el.style.textAlign,
- }),
- },
- ],
- toDOM: (node) => [node.attrs.header ? 'th' : 'td', { align: node.attrs.align }, 0],
- };
- }
-
- toMarkdown(state, node) {
+ ],
+ toDOM: (node) => [node.attrs.header ? 'th' : 'td', { align: node.attrs.align }, 0],
+ },
+ toMarkdown: (state, node) => {
state.renderInline(node);
- }
-}
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/table_head.js b/app/assets/javascripts/behaviors/markdown/nodes/table_head.js
index 4cb94bf088c..2e9b53ee0ac 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/table_head.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/table_head.js
@@ -1,24 +1,14 @@
-/* eslint-disable class-methods-use-this */
-
-import { Node } from 'tiptap';
-
// Transforms generated HTML back to GFM for Banzai::Filter::MarkdownFilter
-export default class TableHead extends Node {
- get name() {
- return 'table_head';
- }
-
- get schema() {
- return {
- content: 'table_header_row',
- parseDOM: [{ tag: 'thead' }],
- toDOM: () => ['thead', 0],
- };
- }
-
- toMarkdown(state, node) {
+export default () => ({
+ name: 'table_head',
+ schema: {
+ content: 'table_header_row',
+ parseDOM: [{ tag: 'thead' }],
+ toDOM: () => ['thead', 0],
+ },
+ toMarkdown: (state, node) => {
state.flushClose(1);
state.renderContent(node);
state.closeBlock(node);
- }
-}
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/table_header_row.js b/app/assets/javascripts/behaviors/markdown/nodes/table_header_row.js
index 2cb2bb9e7fe..d8aa497066c 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/table_header_row.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/table_header_row.js
@@ -1,31 +1,23 @@
-/* eslint-disable class-methods-use-this */
-
import { HIGHER_PARSE_RULE_PRIORITY } from '../constants';
import TableRow from './table_row';
const CENTER_ALIGN = 'center';
// Transforms generated HTML back to GFM for Banzai::Filter::MarkdownFilter
-export default class TableHeaderRow extends TableRow {
- get name() {
- return 'table_header_row';
- }
-
- get schema() {
- return {
- content: 'table_cell+',
- parseDOM: [
- {
- tag: 'thead tr',
- priority: HIGHER_PARSE_RULE_PRIORITY,
- },
- ],
- toDOM: () => ['tr', 0],
- };
- }
-
- toMarkdown(state, node) {
- const cellWidths = super.toMarkdown(state, node);
+export default () => ({
+ name: 'table_header_row',
+ schema: {
+ content: 'table_cell+',
+ parseDOM: [
+ {
+ tag: 'thead tr',
+ priority: HIGHER_PARSE_RULE_PRIORITY,
+ },
+ ],
+ toDOM: () => ['tr', 0],
+ },
+ toMarkdown: (state, node) => {
+ const cellWidths = TableRow().toMarkdown(state, node);
state.flushClose(1);
@@ -40,5 +32,5 @@ export default class TableHeaderRow extends TableRow {
state.write('|');
state.closeBlock(node);
- }
-}
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/table_of_contents.js b/app/assets/javascripts/behaviors/markdown/nodes/table_of_contents.js
index db9072acc3a..4a0256c4644 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/table_of_contents.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/table_of_contents.js
@@ -1,35 +1,26 @@
-/* eslint-disable class-methods-use-this */
-
-import { Node } from 'tiptap';
import { __ } from '~/locale';
import { HIGHER_PARSE_RULE_PRIORITY } from '../constants';
// Transforms generated HTML back to GFM for Banzai::Filter::TableOfContentsFilter
-export default class TableOfContents extends Node {
- get name() {
- return 'table_of_contents';
- }
-
- get schema() {
- return {
- group: 'block',
- atom: true,
- parseDOM: [
- {
- tag: 'ul.section-nav',
- priority: HIGHER_PARSE_RULE_PRIORITY,
- },
- {
- tag: 'p.table-of-contents',
- priority: HIGHER_PARSE_RULE_PRIORITY,
- },
- ],
- toDOM: () => ['p', { class: 'table-of-contents' }, __('Table of Contents')],
- };
- }
-
- toMarkdown(state, node) {
+export default () => ({
+ name: 'table_of_contents',
+ schema: {
+ group: 'block',
+ atom: true,
+ parseDOM: [
+ {
+ tag: 'ul.section-nav',
+ priority: HIGHER_PARSE_RULE_PRIORITY,
+ },
+ {
+ tag: 'p.table-of-contents',
+ priority: HIGHER_PARSE_RULE_PRIORITY,
+ },
+ ],
+ toDOM: () => ['p', { class: 'table-of-contents' }, __('Table of Contents')],
+ },
+ toMarkdown: (state, node) => {
state.write('[[_TOC_]]');
state.closeBlock(node);
- }
-}
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/table_row.js b/app/assets/javascripts/behaviors/markdown/nodes/table_row.js
index 5852502773a..3830dae4f0d 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/table_row.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/table_row.js
@@ -1,22 +1,12 @@
-/* eslint-disable class-methods-use-this */
-
-import { Node } from 'tiptap';
-
// Transforms generated HTML back to GFM for Banzai::Filter::MarkdownFilter
-export default class TableRow extends Node {
- get name() {
- return 'table_row';
- }
-
- get schema() {
- return {
- content: 'table_cell+',
- parseDOM: [{ tag: 'tr' }],
- toDOM: () => ['tr', 0],
- };
- }
-
- toMarkdown(state, node) {
+export default () => ({
+ name: 'table_row',
+ schema: {
+ content: 'table_cell+',
+ parseDOM: [{ tag: 'tr' }],
+ toDOM: () => ['tr', 0],
+ },
+ toMarkdown: (state, node) => {
const cellWidths = [];
state.flushClose(1);
@@ -34,5 +24,5 @@ export default class TableRow extends Node {
state.closeBlock(node);
return cellWidths;
- }
-}
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/task_list.js b/app/assets/javascripts/behaviors/markdown/nodes/task_list.js
index 35ba2eb0674..3c3812ad8f7 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/task_list.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/task_list.js
@@ -1,29 +1,20 @@
-/* eslint-disable class-methods-use-this */
-
-import { Node } from 'tiptap';
import { HIGHER_PARSE_RULE_PRIORITY } from '../constants';
// Transforms generated HTML back to GFM for Banzai::Filter::TaskListFilter
-export default class TaskList extends Node {
- get name() {
- return 'task_list';
- }
-
- get schema() {
- return {
- group: 'block',
- content: '(task_list_item|list_item)+',
- parseDOM: [
- {
- priority: HIGHER_PARSE_RULE_PRIORITY,
- tag: 'ul.task-list',
- },
- ],
- toDOM: () => ['ul', { class: 'task-list' }, 0],
- };
- }
-
+export default () => ({
+ name: 'task_list',
+ schema: {
+ group: 'block',
+ content: '(task_list_item|list_item)+',
+ parseDOM: [
+ {
+ priority: HIGHER_PARSE_RULE_PRIORITY,
+ tag: 'ul.task-list',
+ },
+ ],
+ toDOM: () => ['ul', { class: 'task-list' }, 0],
+ },
toMarkdown(state, node) {
state.renderList(node, ' ', () => '* ');
- }
-}
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/task_list_item.js b/app/assets/javascripts/behaviors/markdown/nodes/task_list_item.js
index 56c2b17286d..10ffce9b1b8 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/task_list_item.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/task_list_item.js
@@ -1,50 +1,38 @@
-/* eslint-disable class-methods-use-this */
-
-import { Node } from 'tiptap';
import { HIGHER_PARSE_RULE_PRIORITY } from '../constants';
// Transforms generated HTML back to GFM for Banzai::Filter::TaskListFilter
-export default class TaskListItem extends Node {
- get name() {
- return 'task_list_item';
- }
-
- get schema() {
- return {
- attrs: {
- done: {
- default: false,
- },
+export default () => ({
+ name: 'task_list_item',
+ schema: {
+ attrs: {
+ done: {
+ default: false,
},
- defining: true,
- draggable: false,
- content: 'paragraph block*',
- parseDOM: [
- {
- priority: HIGHER_PARSE_RULE_PRIORITY,
- tag: 'li.task-list-item',
- getAttrs: (el) => {
- const checkbox = el.querySelector('input[type=checkbox].task-list-item-checkbox');
- return { done: checkbox && checkbox.checked };
- },
+ },
+ defining: true,
+ draggable: false,
+ content: 'paragraph block*',
+ parseDOM: [
+ {
+ priority: HIGHER_PARSE_RULE_PRIORITY,
+ tag: 'li.task-list-item',
+ getAttrs: (el) => {
+ const checkbox = el.querySelector('input[type=checkbox].task-list-item-checkbox');
+ return { done: checkbox && checkbox.checked };
},
- ],
- toDOM(node) {
- return [
- 'li',
- { class: 'task-list-item' },
- [
- 'input',
- { type: 'checkbox', class: 'task-list-item-checkbox', checked: node.attrs.done },
- ],
- ['div', { class: 'todo-content' }, 0],
- ];
},
- };
- }
-
+ ],
+ toDOM(node) {
+ return [
+ 'li',
+ { class: 'task-list-item' },
+ ['input', { type: 'checkbox', class: 'task-list-item-checkbox', checked: node.attrs.done }],
+ ['div', { class: 'todo-content' }, 0],
+ ];
+ },
+ },
toMarkdown(state, node) {
state.write(`[${node.attrs.done ? 'x' : ' '}] `);
state.renderContent(node);
- }
-}
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/text.js b/app/assets/javascripts/behaviors/markdown/nodes/text.js
index 0dc77a12f5c..0e1f0bc0e40 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/text.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/text.js
@@ -1,20 +1,11 @@
-/* eslint-disable class-methods-use-this */
-
-import { Node } from 'tiptap';
import { defaultMarkdownSerializer } from '~/lib/prosemirror_markdown_serializer';
-export default class Text extends Node {
- get name() {
- return 'text';
- }
-
- get schema() {
- return {
- group: 'inline',
- };
- }
-
+export default () => ({
+ name: 'text',
+ schema: {
+ group: 'inline',
+ },
toMarkdown(state, node) {
defaultMarkdownSerializer.nodes.text(state, node);
- }
-}
+ },
+});
diff --git a/app/assets/javascripts/behaviors/markdown/nodes/video.js b/app/assets/javascripts/behaviors/markdown/nodes/video.js
index 68085c2c416..aa1088826da 100644
--- a/app/assets/javascripts/behaviors/markdown/nodes/video.js
+++ b/app/assets/javascripts/behaviors/markdown/nodes/video.js
@@ -1,10 +1,4 @@
-import Playable from './playable';
+import playable from './playable';
// Transforms generated HTML back to GFM for Banzai::Filter::VideoLinkFilter
-export default class Video extends Playable {
- constructor() {
- super();
- this.mediaType = 'video';
- this.extraElementAttrs = { width: '400' };
- }
-}
+export default () => playable({ mediaType: 'video', extraElementAttrs: { width: '400' } });
diff --git a/app/assets/javascripts/behaviors/markdown/render_sandboxed_mermaid.js b/app/assets/javascripts/behaviors/markdown/render_sandboxed_mermaid.js
index 1d54a1b0c04..85a991a1ec9 100644
--- a/app/assets/javascripts/behaviors/markdown/render_sandboxed_mermaid.js
+++ b/app/assets/javascripts/behaviors/markdown/render_sandboxed_mermaid.js
@@ -88,7 +88,7 @@ function renderMermaidEl(el, source) {
const iframeEl = document.createElement('iframe');
setAttributes(iframeEl, {
src: getSandboxFrameSrc(),
- sandbox: 'allow-scripts',
+ sandbox: 'allow-scripts allow-popups',
frameBorder: 0,
scrolling: 'no',
width: '100%',
diff --git a/app/assets/javascripts/behaviors/markdown/schema.js b/app/assets/javascripts/behaviors/markdown/schema.js
index 8bea24584cc..1b0f46ff4cb 100644
--- a/app/assets/javascripts/behaviors/markdown/schema.js
+++ b/app/assets/javascripts/behaviors/markdown/schema.js
@@ -1,24 +1,20 @@
import { Schema } from 'prosemirror-model';
import editorExtensions from './editor_extensions';
-const nodes = editorExtensions
- .filter((extension) => extension.type === 'node')
- .reduce(
- (ns, { name, schema }) => ({
- ...ns,
- [name]: schema,
- }),
- {},
- );
+const nodes = editorExtensions.nodes.reduce(
+ (ns, { name, schema }) => ({
+ ...ns,
+ [name]: schema,
+ }),
+ {},
+);
-const marks = editorExtensions
- .filter((extension) => extension.type === 'mark')
- .reduce(
- (ms, { name, schema }) => ({
- ...ms,
- [name]: schema,
- }),
- {},
- );
+const marks = editorExtensions.marks.reduce(
+ (ms, { name, schema }) => ({
+ ...ms,
+ [name]: schema,
+ }),
+ {},
+);
export default new Schema({ nodes, marks });
diff --git a/app/assets/javascripts/behaviors/markdown/serializer.js b/app/assets/javascripts/behaviors/markdown/serializer.js
index a5f97d7748a..e3e8a380cd5 100644
--- a/app/assets/javascripts/behaviors/markdown/serializer.js
+++ b/app/assets/javascripts/behaviors/markdown/serializer.js
@@ -1,24 +1,20 @@
import { MarkdownSerializer } from '~/lib/prosemirror_markdown_serializer';
import editorExtensions from './editor_extensions';
-const nodes = editorExtensions
- .filter((extension) => extension.type === 'node')
- .reduce(
- (ns, { name, toMarkdown }) => ({
- ...ns,
- [name]: toMarkdown,
- }),
- {},
- );
+const nodes = editorExtensions.nodes.reduce(
+ (ns, { name, toMarkdown }) => ({
+ ...ns,
+ [name]: toMarkdown,
+ }),
+ {},
+);
-const marks = editorExtensions
- .filter((extension) => extension.type === 'mark')
- .reduce(
- (ms, { name, toMarkdown }) => ({
- ...ms,
- [name]: toMarkdown,
- }),
- {},
- );
+const marks = editorExtensions.marks.reduce(
+ (ms, { name, toMarkdown }) => ({
+ ...ms,
+ [name]: toMarkdown,
+ }),
+ {},
+);
export default new MarkdownSerializer(nodes, marks);