Commit 5b17c438 authored by Kushal Pandya's avatar Kushal Pandya

Merge branch '338272-content-editor-inline-diff' into 'master'

Add support for inline diff in content editor

See merge request gitlab-org/gitlab!68231
parents 9bf5a622 c10baec8
import { Mark, markInputRule, mergeAttributes } from '@tiptap/core';
export const inputRegexAddition = /(\{\+(.+?)\+\})$/gm;
export const inputRegexDeletion = /(\{-(.+?)-\})$/gm;
export default Mark.create({
name: 'inlineDiff',
defaultOptions: {
HTMLAttributes: {},
},
addAttributes() {
return {
type: {
default: 'addition',
parseHTML: (element) => {
return {
type: element.classList.contains('deletion') ? 'deletion' : 'addition',
};
},
},
};
},
parseHTML() {
return [
{
tag: 'span.idiff',
},
];
},
renderHTML({ HTMLAttributes: { type, ...HTMLAttributes } }) {
return [
'span',
mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {
class: `idiff left right ${type}`,
}),
0,
];
},
addInputRules() {
return [
markInputRule(inputRegexAddition, this.type, () => ({ type: 'addition' })),
markInputRule(inputRegexDeletion, this.type, () => ({ type: 'deletion' })),
];
},
});
...@@ -16,6 +16,7 @@ import Heading from '../extensions/heading'; ...@@ -16,6 +16,7 @@ import Heading from '../extensions/heading';
import History from '../extensions/history'; import History from '../extensions/history';
import HorizontalRule from '../extensions/horizontal_rule'; import HorizontalRule from '../extensions/horizontal_rule';
import Image from '../extensions/image'; import Image from '../extensions/image';
import InlineDiff from '../extensions/inline_diff';
import Italic from '../extensions/italic'; import Italic from '../extensions/italic';
import Link from '../extensions/link'; import Link from '../extensions/link';
import ListItem from '../extensions/list_item'; import ListItem from '../extensions/list_item';
...@@ -74,6 +75,7 @@ export const createContentEditor = ({ ...@@ -74,6 +75,7 @@ export const createContentEditor = ({
History, History,
HorizontalRule, HorizontalRule,
Image, Image,
InlineDiff,
Italic, Italic,
Link, Link,
ListItem, ListItem,
......
...@@ -13,6 +13,7 @@ import HardBreak from '../extensions/hard_break'; ...@@ -13,6 +13,7 @@ import HardBreak from '../extensions/hard_break';
import Heading from '../extensions/heading'; import Heading from '../extensions/heading';
import HorizontalRule from '../extensions/horizontal_rule'; import HorizontalRule from '../extensions/horizontal_rule';
import Image from '../extensions/image'; import Image from '../extensions/image';
import InlineDiff from '../extensions/inline_diff';
import Italic from '../extensions/italic'; import Italic from '../extensions/italic';
import Link from '../extensions/link'; import Link from '../extensions/link';
import ListItem from '../extensions/list_item'; import ListItem from '../extensions/list_item';
...@@ -36,6 +37,15 @@ const defaultSerializerConfig = { ...@@ -36,6 +37,15 @@ const defaultSerializerConfig = {
[Italic.name]: { open: '_', close: '_', mixable: true, expelEnclosingWhitespace: true }, [Italic.name]: { open: '_', close: '_', mixable: true, expelEnclosingWhitespace: true },
[Subscript.name]: { open: '<sub>', close: '</sub>', mixable: true }, [Subscript.name]: { open: '<sub>', close: '</sub>', mixable: true },
[Superscript.name]: { open: '<sup>', close: '</sup>', mixable: true }, [Superscript.name]: { open: '<sup>', close: '</sup>', mixable: true },
[InlineDiff.name]: {
mixable: true,
open(state, mark) {
return mark.attrs.type === 'addition' ? '{+' : '{-';
},
close(state, mark) {
return mark.attrs.type === 'addition' ? '+}' : '-}';
},
},
[Link.name]: { [Link.name]: {
open() { open() {
return '['; return '[';
......
import { inputRegexAddition, inputRegexDeletion } from '~/content_editor/extensions/inline_diff';
describe('content_editor/extensions/inline_diff', () => {
describe.each`
inputRegex | description | input | matches
${inputRegexAddition} | ${'inputRegexAddition'} | ${'hello{+world+}'} | ${true}
${inputRegexAddition} | ${'inputRegexAddition'} | ${'hello{+ world +}'} | ${true}
${inputRegexAddition} | ${'inputRegexAddition'} | ${'hello {+ world+}'} | ${true}
${inputRegexAddition} | ${'inputRegexAddition'} | ${'{+hello world +}'} | ${true}
${inputRegexAddition} | ${'inputRegexAddition'} | ${'{+hello with \nnewline+}'} | ${false}
${inputRegexAddition} | ${'inputRegexAddition'} | ${'{+open only'} | ${false}
${inputRegexAddition} | ${'inputRegexAddition'} | ${'close only+}'} | ${false}
${inputRegexDeletion} | ${'inputRegexDeletion'} | ${'hello{-world-}'} | ${true}
${inputRegexDeletion} | ${'inputRegexDeletion'} | ${'hello{- world -}'} | ${true}
${inputRegexDeletion} | ${'inputRegexDeletion'} | ${'hello {- world-}'} | ${true}
${inputRegexDeletion} | ${'inputRegexDeletion'} | ${'{-hello world -}'} | ${true}
${inputRegexDeletion} | ${'inputRegexDeletion'} | ${'{+hello with \nnewline+}'} | ${false}
${inputRegexDeletion} | ${'inputRegexDeletion'} | ${'{-open only'} | ${false}
${inputRegexDeletion} | ${'inputRegexDeletion'} | ${'close only-}'} | ${false}
`('$description', ({ inputRegex, input, matches }) => {
it(`${matches ? 'matches' : 'does not match'}: "${input}"`, () => {
const match = new RegExp(inputRegex).test(input);
expect(match).toBe(matches);
});
});
});
...@@ -8,6 +8,10 @@ ...@@ -8,6 +8,10 @@
markdown: '_emphasized text_' markdown: '_emphasized text_'
- name: inline_code - name: inline_code
markdown: '`code`' markdown: '`code`'
- name: inline_diff
markdown: |-
* {-deleted-}
* {+added+}
- name: subscript - name: subscript
markdown: H<sub>2</sub>O markdown: H<sub>2</sub>O
- name: superscript - name: superscript
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment