Commit 3e60388d authored by Enrique Alcantara's avatar Enrique Alcantara

Support math expressions in the Content Editor

Render inline math expressions in the Content
Editor and allow to create new ones using an
input rule

Changelog: added
parent f736f85c
import { Mark, markInputRule } from '@tiptap/core';
import { __ } from '~/locale';
import { PARSE_HTML_PRIORITY_HIGHEST } from '../constants';
export const inputRegex = /(?:^|\s)\$`([^`]+)`\$$/gm;
export default Mark.create({
name: 'mathInline',
parseHTML() {
return [
{
tag: 'code.math[data-math-style=inline]',
priority: PARSE_HTML_PRIORITY_HIGHEST,
},
];
},
renderHTML({ HTMLAttributes }) {
return [
'code',
{
title: __('Inline math'),
'data-toggle': 'tooltip',
class: 'gl-inset-border-1-gray-400',
...HTMLAttributes,
},
0,
];
},
addInputRules() {
return [markInputRule(inputRegex, this.type)];
},
});
......@@ -32,6 +32,7 @@ import Italic from '../extensions/italic';
import Link from '../extensions/link';
import ListItem from '../extensions/list_item';
import Loading from '../extensions/loading';
import MathInline from '../extensions/math_inline';
import OrderedList from '../extensions/ordered_list';
import Paragraph from '../extensions/paragraph';
import Reference from '../extensions/reference';
......@@ -106,6 +107,7 @@ export const createContentEditor = ({
Link,
ListItem,
Loading,
MathInline,
OrderedList,
Paragraph,
Reference,
......
......@@ -27,6 +27,7 @@ import InlineDiff from '../extensions/inline_diff';
import Italic from '../extensions/italic';
import Link from '../extensions/link';
import ListItem from '../extensions/list_item';
import MathInline from '../extensions/math_inline';
import OrderedList from '../extensions/ordered_list';
import Paragraph from '../extensions/paragraph';
import Reference from '../extensions/reference';
......@@ -86,6 +87,11 @@ const defaultSerializerConfig = {
: `](${state.esc(href)}${mark.attrs.title ? ` ${state.quote(mark.attrs.title)}` : ''})`;
},
},
[MathInline.name]: {
open: (...args) => `$${defaultMarkdownSerializer.marks.code.open(...args)}`,
close: (...args) => `${defaultMarkdownSerializer.marks.code.close(...args)}$`,
escape: false,
},
[Strike.name]: {
open: '~~',
close: '~~',
......
......@@ -18176,6 +18176,9 @@ msgstr ""
msgid "Inline"
msgstr ""
msgid "Inline math"
msgstr ""
msgid "Input host keys manually"
msgstr ""
......
import MathInline from '~/content_editor/extensions/math_inline';
import { createTestEditor, createDocBuilder } from '../test_utils';
describe('content_editor/extensions/math_inline', () => {
let tiptapEditor;
let doc;
let p;
let mathInline;
beforeEach(() => {
tiptapEditor = createTestEditor({ extensions: [MathInline] });
({
builders: { doc, p, mathInline },
} = createDocBuilder({
tiptapEditor,
names: {
details: { markType: MathInline.name },
},
}));
});
it.each`
input | insertedNode
${'$`a^2`$'} | ${() => p(mathInline('a^2'))}
${'$`a^2`'} | ${() => p('$`a^2`')}
${'`a^2`$'} | ${() => p('`a^2`$')}
`('with input=$input, then should insert a $insertedNode', ({ input, insertedNode }) => {
const { view } = tiptapEditor;
const expectedDoc = doc(insertedNode());
tiptapEditor.chain().setContent(input).setTextSelection(0).run();
const { state } = tiptapEditor;
const { selection } = state;
// Triggers the event handler that input rules listen to
view.someProp('handleTextInput', (f) => f(view, selection.from, input.length + 1, input));
expect(tiptapEditor.getJSON()).toEqual(expectedDoc.toJSON());
});
});
......@@ -278,3 +278,12 @@
- `RGBA(0,255,0,0.3)`
- `HSL(540,70%,50%)`
- `HSLA(540,70%,50%,0.3)`
- name: math
markdown: |-
This math is inline $`a^2+b^2=c^2`$.
This is on a separate line:
```math
a^2+b^2=c^2
```
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