Commit c6a03fc3 authored by Enrique Alcántara's avatar Enrique Alcántara Committed by Frédéric Caplette

Allow to insert highlighted code blocks in the Content Editor

parent 66618af0
...@@ -80,6 +80,15 @@ export default { ...@@ -80,6 +80,15 @@ export default {
:tiptap-editor="contentEditor.tiptapEditor" :tiptap-editor="contentEditor.tiptapEditor"
@execute="trackToolbarControlExecution" @execute="trackToolbarControlExecution"
/> />
<toolbar-button
data-testid="code-block"
content-type="codeBlock"
icon-name="doc-code"
editor-command="toggleCodeBlock"
:label="__('Insert a code block')"
:tiptap-editor="contentEditor.tiptapEditor"
@execute="trackToolbarControlExecution"
/>
<toolbar-button <toolbar-button
data-testid="bullet-list" data-testid="bullet-list"
content-type="bulletList" content-type="bulletList"
......
import { CodeBlockLowlight } from '@tiptap/extension-code-block-lowlight'; import { CodeBlockLowlight } from '@tiptap/extension-code-block-lowlight';
import * as lowlight from 'lowlight';
import { defaultMarkdownSerializer } from 'prosemirror-markdown/src/to_markdown'; import { defaultMarkdownSerializer } from 'prosemirror-markdown/src/to_markdown';
const extractLanguage = (element) => element.getAttribute('lang'); const extractLanguage = (element) => element.getAttribute('lang');
...@@ -6,7 +7,14 @@ const extractLanguage = (element) => element.getAttribute('lang'); ...@@ -6,7 +7,14 @@ const extractLanguage = (element) => element.getAttribute('lang');
const ExtendedCodeBlockLowlight = CodeBlockLowlight.extend({ const ExtendedCodeBlockLowlight = CodeBlockLowlight.extend({
addAttributes() { addAttributes() {
return { return {
...this.parent(), language: {
default: null,
parseHTML: (element) => {
return {
language: extractLanguage(element),
};
},
},
/* `params` is the name of the attribute that /* `params` is the name of the attribute that
prosemirror-markdown uses to extract the language prosemirror-markdown uses to extract the language
of a codeblock. of a codeblock.
...@@ -19,8 +27,16 @@ const ExtendedCodeBlockLowlight = CodeBlockLowlight.extend({ ...@@ -19,8 +27,16 @@ const ExtendedCodeBlockLowlight = CodeBlockLowlight.extend({
}; };
}, },
}, },
class: {
default: 'code highlight js-syntax-highlight',
},
}; };
}, },
renderHTML({ HTMLAttributes }) {
return ['pre', HTMLAttributes, ['code', {}, 0]];
},
}).configure({
lowlight,
}); });
export const tiptapExtension = ExtendedCodeBlockLowlight; export const tiptapExtension = ExtendedCodeBlockLowlight;
......
@import 'mixins_and_variables_and_functions'; @import 'mixins_and_variables_and_functions';
@import 'highlight.js/scss/a11y-light';
.title .edit-wiki-header { .title .edit-wiki-header {
width: 780px; width: 780px;
......
...@@ -138,6 +138,7 @@ ...@@ -138,6 +138,7 @@
"jszip-utils": "^0.0.2", "jszip-utils": "^0.0.2",
"katex": "^0.13.2", "katex": "^0.13.2",
"lodash": "^4.17.20", "lodash": "^4.17.20",
"lowlight": "^1.20.0",
"marked": "^0.3.12", "marked": "^0.3.12",
"mathjax": "3", "mathjax": "3",
"mermaid": "^8.9.2", "mermaid": "^8.9.2",
......
...@@ -46,6 +46,7 @@ describe('content_editor/components/top_toolbar', () => { ...@@ -46,6 +46,7 @@ describe('content_editor/components/top_toolbar', () => {
${'blockquote'} | ${{ contentType: 'blockquote', iconName: 'quote', label: 'Insert a quote', editorCommand: 'toggleBlockquote' }} ${'blockquote'} | ${{ contentType: 'blockquote', iconName: 'quote', label: 'Insert a quote', editorCommand: 'toggleBlockquote' }}
${'bullet-list'} | ${{ contentType: 'bulletList', iconName: 'list-bulleted', label: 'Add a bullet list', editorCommand: 'toggleBulletList' }} ${'bullet-list'} | ${{ contentType: 'bulletList', iconName: 'list-bulleted', label: 'Add a bullet list', editorCommand: 'toggleBulletList' }}
${'ordered-list'} | ${{ contentType: 'orderedList', iconName: 'list-numbered', label: 'Add a numbered list', editorCommand: 'toggleOrderedList' }} ${'ordered-list'} | ${{ contentType: 'orderedList', iconName: 'list-numbered', label: 'Add a numbered list', editorCommand: 'toggleOrderedList' }}
${'code-block'} | ${{ contentType: 'codeBlock', iconName: 'doc-code', label: 'Insert a code block', editorCommand: 'toggleCodeBlock' }}
${'text-styles'} | ${{}} ${'text-styles'} | ${{}}
`('given a $testId toolbar control', ({ testId, controlProps }) => { `('given a $testId toolbar control', ({ testId, controlProps }) => {
beforeEach(() => { beforeEach(() => {
......
import { tiptapExtension as CodeBlockHighlight } from '~/content_editor/extensions/code_block_highlight';
import { loadMarkdownApiResult } from '../markdown_processing_examples';
import { createTestEditor } from '../test_utils';
describe('content_editor/extensions/code_block_highlight', () => {
let codeBlockHtmlFixture;
let parsedCodeBlockHtmlFixture;
let tiptapEditor;
const parseHTML = (html) => new DOMParser().parseFromString(html, 'text/html');
const preElement = () => parsedCodeBlockHtmlFixture.querySelector('pre');
beforeEach(() => {
const { html } = loadMarkdownApiResult('code_block');
tiptapEditor = createTestEditor({ extensions: [CodeBlockHighlight] });
codeBlockHtmlFixture = html;
parsedCodeBlockHtmlFixture = parseHTML(codeBlockHtmlFixture);
tiptapEditor.commands.setContent(codeBlockHtmlFixture);
});
it('extracts language and params attributes from Markdown API output', () => {
const language = preElement().getAttribute('lang');
expect(tiptapEditor.getJSON().content[0].attrs).toMatchObject({
language,
params: language,
});
});
it('adds code, highlight, and js-syntax-highlight to code block element', () => {
const editorHtmlOutput = parseHTML(tiptapEditor.getHTML()).querySelector('pre');
expect(editorHtmlOutput.classList.toString()).toContain('code highlight js-syntax-highlight');
});
});
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