diff options
Diffstat (limited to 'app/assets/javascripts/behaviors/markdown/nodes')
32 files changed, 547 insertions, 721 deletions
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' } }); |