Merge pull request #15 from ueberdosis/feature/parse-code-blocks
Add language support to Code Block’s parseDOM function
This commit is contained in:
@@ -3,6 +3,7 @@ module.exports = {
|
|||||||
'@babel/preset-env',
|
'@babel/preset-env',
|
||||||
],
|
],
|
||||||
plugins: [
|
plugins: [
|
||||||
|
'@babel/plugin-proposal-nullish-coalescing-operator',
|
||||||
'@babel/plugin-proposal-optional-chaining',
|
'@babel/plugin-proposal-optional-chaining',
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,6 +69,16 @@ context('/api/extensions/code-block', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should parse the language from a HTML code block', () => {
|
||||||
|
cy.get('.ProseMirror').then(([{ editor }]) => {
|
||||||
|
editor.setContent('<pre><code class="language-css">body { display: none; }</code></pre>')
|
||||||
|
|
||||||
|
cy.get('.ProseMirror')
|
||||||
|
.find('pre>code.language-css')
|
||||||
|
.should('have.length', 1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
it('should make a code block for js', () => {
|
it('should make a code block for js', () => {
|
||||||
cy.get('.ProseMirror').then(([{ editor }]) => {
|
cy.get('.ProseMirror').then(([{ editor }]) => {
|
||||||
editor.clearContent()
|
editor.clearContent()
|
||||||
|
|||||||
@@ -17,9 +17,10 @@ yarn add @tiptap/extension-code-block
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Settings
|
## Settings
|
||||||
| Option | Type | Default | Description |
|
| Option | Type | Default | Description |
|
||||||
| ------ | ------ | ------- | -------------------------------------------- |
|
| ------------------- | ------ | --------- | ---------------------------------------------------------------- |
|
||||||
| class | string | – | Add a custom class to the rendered HTML tag. |
|
| class | string | – | Add a custom class to the rendered HTML tag. |
|
||||||
|
| languageClassPrefix | string | language- | Adds a prefix to language classes that are applied to code tags. |
|
||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
| Command | Options | Description |
|
| Command | Options | Description |
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
"reset": "yarn clean:packages && rm -rf ./**/.cache && rm -rf ./**/node_modules && rm -rf ./yarn.lock && yarn install"
|
"reset": "yarn clean:packages && rm -rf ./**/.cache && rm -rf ./**/node_modules && rm -rf ./yarn.lock && yarn install"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.10.4",
|
||||||
"@babel/plugin-proposal-optional-chaining": "^7.11.0",
|
"@babel/plugin-proposal-optional-chaining": "^7.11.0",
|
||||||
"@babel/preset-env": "^7.11.5",
|
"@babel/preset-env": "^7.11.5",
|
||||||
"@types/prosemirror-commands": "^1.0.3",
|
"@types/prosemirror-commands": "^1.0.3",
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
import { Command, Node } from '@tiptap/core'
|
import { Command, Node } from '@tiptap/core'
|
||||||
import { textblockTypeInputRule } from 'prosemirror-inputrules'
|
import { textblockTypeInputRule } from 'prosemirror-inputrules'
|
||||||
|
|
||||||
|
export interface CodeBlockOptions {
|
||||||
|
languageClassPrefix: string,
|
||||||
|
}
|
||||||
|
|
||||||
export type CodeBlockCommand = () => Command
|
export type CodeBlockCommand = () => Command
|
||||||
|
|
||||||
declare module '@tiptap/core/src/Editor' {
|
declare module '@tiptap/core/src/Editor' {
|
||||||
@@ -11,9 +15,12 @@ declare module '@tiptap/core/src/Editor' {
|
|||||||
|
|
||||||
export const inputRegex = /^```(?<language>[a-z]*)? $/
|
export const inputRegex = /^```(?<language>[a-z]*)? $/
|
||||||
|
|
||||||
export default new Node()
|
export default new Node<CodeBlockOptions>()
|
||||||
.name('code_block')
|
.name('code_block')
|
||||||
.schema(() => ({
|
.defaults({
|
||||||
|
languageClassPrefix: 'language-',
|
||||||
|
})
|
||||||
|
.schema(({ options }) => ({
|
||||||
attrs: {
|
attrs: {
|
||||||
language: {
|
language: {
|
||||||
default: null,
|
default: null,
|
||||||
@@ -26,9 +33,25 @@ export default new Node()
|
|||||||
defining: true,
|
defining: true,
|
||||||
draggable: false,
|
draggable: false,
|
||||||
parseDOM: [
|
parseDOM: [
|
||||||
{ tag: 'pre', preserveWhitespace: 'full' },
|
{
|
||||||
|
tag: 'pre',
|
||||||
|
preserveWhitespace: 'full',
|
||||||
|
getAttrs(node) {
|
||||||
|
const classAttribute = (node as Element).firstElementChild?.getAttribute('class')
|
||||||
|
|
||||||
|
if (!classAttribute) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const regexLanguageClassPrefix = new RegExp(`^(${options.languageClassPrefix})`)
|
||||||
|
|
||||||
|
return { language: classAttribute.replace(regexLanguageClassPrefix, '') }
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
toDOM: node => ['pre', ['code', { class: node.attrs.language && `language-${node.attrs.language}` }, 0]],
|
toDOM: node => ['pre', ['code', {
|
||||||
|
class: node.attrs.language && options.languageClassPrefix + node.attrs.language,
|
||||||
|
}, 0]],
|
||||||
}))
|
}))
|
||||||
.commands(({ name }) => ({
|
.commands(({ name }) => ({
|
||||||
codeBlock: attrs => ({ commands }) => {
|
codeBlock: attrs => ({ commands }) => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "esnext",
|
"target": "es2019",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"jsx": "preserve",
|
"jsx": "preserve",
|
||||||
|
|||||||
Reference in New Issue
Block a user