Commit 3de274ca authored by Paul Slaughter's avatar Paul Slaughter Committed by Enrique Alcántara

Add Table of Contents Content Editor Extension

parent c60c141d
import { Node, nodeInputRule } from '@tiptap/core';
import { s__ } from '~/locale';
import { PARSE_HTML_PRIORITY_HIGHEST } from '../constants';
export const inputRuleRegExps = [/^\[\[_TOC_\]\]$/, /^\[TOC\]$/];
export default Node.create({
name: 'tableOfContents',
inline: false,
group: 'block',
parseHTML() {
return [
{
tag: 'ul.section-nav',
priority: PARSE_HTML_PRIORITY_HIGHEST,
},
];
},
renderHTML() {
return [
'div',
{
class:
'table-of-contents gl-border-1 gl-border-solid gl-text-center gl-border-gray-100 gl-mb-5',
},
s__('ContentEditor|Table of Contents'),
];
},
addInputRules() {
return inputRuleRegExps.map((regex) => nodeInputRule(regex, this.type));
},
});
...@@ -37,6 +37,7 @@ import Superscript from '../extensions/superscript'; ...@@ -37,6 +37,7 @@ import Superscript from '../extensions/superscript';
import Table from '../extensions/table'; import Table from '../extensions/table';
import TableCell from '../extensions/table_cell'; import TableCell from '../extensions/table_cell';
import TableHeader from '../extensions/table_header'; import TableHeader from '../extensions/table_header';
import TableOfContents from '../extensions/table_of_contents';
import TableRow from '../extensions/table_row'; import TableRow from '../extensions/table_row';
import TaskItem from '../extensions/task_item'; import TaskItem from '../extensions/task_item';
import TaskList from '../extensions/task_list'; import TaskList from '../extensions/task_list';
...@@ -104,6 +105,7 @@ export const createContentEditor = ({ ...@@ -104,6 +105,7 @@ export const createContentEditor = ({
Superscript, Superscript,
TableCell, TableCell,
TableHeader, TableHeader,
TableOfContents,
TableRow, TableRow,
Table, Table,
TaskItem, TaskItem,
......
...@@ -33,6 +33,7 @@ import Superscript from '../extensions/superscript'; ...@@ -33,6 +33,7 @@ import Superscript from '../extensions/superscript';
import Table from '../extensions/table'; import Table from '../extensions/table';
import TableCell from '../extensions/table_cell'; import TableCell from '../extensions/table_cell';
import TableHeader from '../extensions/table_header'; import TableHeader from '../extensions/table_header';
import TableOfContents from '../extensions/table_of_contents';
import TableRow from '../extensions/table_row'; import TableRow from '../extensions/table_row';
import TaskItem from '../extensions/task_item'; import TaskItem from '../extensions/task_item';
import TaskList from '../extensions/task_list'; import TaskList from '../extensions/task_list';
...@@ -147,6 +148,10 @@ const defaultSerializerConfig = { ...@@ -147,6 +148,10 @@ const defaultSerializerConfig = {
[Reference.name]: (state, node) => { [Reference.name]: (state, node) => {
state.write(node.attrs.originalText || node.attrs.text); state.write(node.attrs.originalText || node.attrs.text);
}, },
[TableOfContents.name]: (state, node) => {
state.write('[[_TOC_]]');
state.closeBlock(node);
},
[Table.name]: renderTable, [Table.name]: renderTable,
[TableCell.name]: renderTableCell, [TableCell.name]: renderTableCell,
[TableHeader.name]: renderTableCell, [TableHeader.name]: renderTableCell,
......
...@@ -9057,6 +9057,9 @@ msgstr "" ...@@ -9057,6 +9057,9 @@ msgstr ""
msgid "Content parsed with %{link}." msgid "Content parsed with %{link}."
msgstr "" msgstr ""
msgid "ContentEditor|Table of Contents"
msgstr ""
msgid "ContentEditor|You have to provide a renderMarkdown function or a custom serializer" msgid "ContentEditor|You have to provide a renderMarkdown function or a custom serializer"
msgstr "" msgstr ""
......
import TableOfContents from '~/content_editor/extensions/table_of_contents';
import { createTestEditor } from '../test_utils';
describe('content_editor/extensions/emoji', () => {
let tiptapEditor;
beforeEach(() => {
tiptapEditor = createTestEditor({ extensions: [TableOfContents] });
});
it.each`
input | insertedNodeName
${'[[_TOC_]]'} | ${TableOfContents.name}
${'[TOC]'} | ${TableOfContents.name}
${'[toc]'} | ${'paragraph'}
${'TOC'} | ${'paragraph'}
${'[_TOC_]'} | ${'paragraph'}
${'[[TOC]]'} | ${'paragraph'}
`('with input=$input, then should insert a $insertedNodeName', ({ input, insertedNodeName }) => {
const { view } = tiptapEditor;
const { selection } = view.state;
// Triggers the event handler that input rules listen to
view.someProp('handleTextInput', (f) => f(view, selection.from, selection.to, input));
expect(tiptapEditor.state.doc.content.content).toEqual([
expect.objectContaining({
type: expect.objectContaining({
name: insertedNodeName,
}),
}),
]);
});
});
...@@ -204,3 +204,18 @@ ...@@ -204,3 +204,18 @@
* [x] ![Sample Audio](https://gitlab.com/1.mp3) * [x] ![Sample Audio](https://gitlab.com/1.mp3)
* [x] ![Sample Audio](https://gitlab.com/2.mp3) * [x] ![Sample Audio](https://gitlab.com/2.mp3)
* [x] ![Sample Video](https://gitlab.com/3.mp4) * [x] ![Sample Video](https://gitlab.com/3.mp4)
- name: table_of_contents
markdown: |-
[[_TOC_]]
# Lorem
Well, that's just like... your opinion.. man.
## Ipsum
### Dolar
# Sit amit
### I don't know
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