Skip to content

Commit

Permalink
Merge pull request #3523 from nextcloud/fix/list-style
Browse files Browse the repository at this point in the history
Preserve bullet list style and change default style to `-`
  • Loading branch information
max-nextcloud authored Dec 7, 2022
2 parents c748659 + 6c0d07f commit 116f141
Show file tree
Hide file tree
Showing 25 changed files with 205 additions and 118 deletions.
4 changes: 2 additions & 2 deletions cypress/e2e/ListItem.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import TaskItem from './../../src/nodes/TaskItem.js'
import BulletList from './../../src/nodes/BulletList.js'
import Markdown, { createMarkdownSerializer } from './../../src/extensions/Markdown.js'
import { findChildren } from 'prosemirror-utils'
import createEditor from './../../src/tests/createEditor.js'
import { createCustomEditor } from './../support/components.js'
import testData from '../fixtures/ListItem.md'
import markdownit from './../../src/markdownit/index.js'

describe('ListItem extension integrated in the editor', () => {

const editor = createEditor({
const editor = createCustomEditor({
content: '',
extensions: [
Markdown,
Expand Down
11 changes: 6 additions & 5 deletions cypress/e2e/Table.spec.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { User } from '@nextcloud/cypress'
import { findChildren } from 'prosemirror-utils'
import { initUserAndFiles, randHash } from '../utils/index.js'
import { createCustomEditor } from './../support/components.js'

import markdownit from './../../src/markdownit/index.js'
import testData from '../fixtures/Table.md'
import createEditor from './../../src/tests/createEditor.js'
import EditableTable from './../../src/nodes/EditableTable.js'
import Markdown, { createMarkdownSerializer } from './../../src/extensions/Markdown.js'

import { User } from '@nextcloud/cypress'
import { initUserAndFiles, randHash } from '../utils/index.js'
import testData from '../fixtures/Table.md'

const randUser = new User(randHash(), 'password')
const fileName = 'empty.md'
Expand Down Expand Up @@ -125,7 +126,7 @@ describe('table plugin', () => {

describe('Table extension integrated in the editor', () => {

const editor = createEditor({
const editor = createCustomEditor({
content: '',
extensions: [
Markdown,
Expand Down
10 changes: 5 additions & 5 deletions cypress/fixtures/ListItem.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@

---

* [ ] did toggleTaskList
- [ ] did toggleTaskList

* keep

Expand Down Expand Up @@ -76,7 +76,7 @@ toggleBulletList

---

* did toggleBulletList
- did toggleBulletList

## Splits bullet list when turning one item into task

Expand All @@ -85,7 +85,7 @@ toggleBulletList

---

* [ ] did toggleTaskList
- [ ] did toggleTaskList

* not todo

Expand All @@ -97,11 +97,11 @@ toggleBulletList

---

* [ ] did toggleTaskList
- [ ] did toggleTaskList

* not todo

* [ ] did toggleTaskList
- [ ] did toggleTaskList

## toggle off task list item should turn it into normal list item

Expand Down
11 changes: 11 additions & 0 deletions cypress/support/components.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Editor } from '@tiptap/core'
import { Document } from '@tiptap/extension-document'
import { Text } from '@tiptap/extension-text'
import Paragraph from '../../src/nodes/Paragraph.js'

export const createCustomEditor = ({ content, extensions }) => {
return new Editor({
content,
extensions: [Document, Paragraph, Text, ...extensions],
})
}
4 changes: 2 additions & 2 deletions js/editor.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/editor.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions js/text-files.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/text-files.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions js/text-public.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/text-public.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions js/text-text.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/text-text.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions js/text-viewer.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/text-viewer.js.map

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions src/markdownit/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,13 @@ const markdownit = MarkdownIt('commonmark', { html: false, breaks: false })
// Render front matter tokens
markdownit.renderer.rules.front_matter = (tokens, idx, options) => `<pre id="frontmatter"><code>${escapeHtml(tokens[idx].meta)}</code></pre>`

// Render lists with bullet attribute
markdownit.renderer.rules.bullet_list_open = (tokens, idx, options) => {
tokens[idx].attrs = [
...(tokens[idx].attrs || []),
['data-bullet', tokens[idx].markup],
]
return markdownit.renderer.renderToken(tokens, idx, options)
}

export default markdownit
3 changes: 2 additions & 1 deletion src/markdownit/splitMixedLists.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
*/

/**
* @param {object} md Markdown object
* @param {import('markdown-it')} md Markdown object
*/
export default function splitMixedLists(md) {
md.core.ruler.after('task-lists', 'split-mixed-task-lists', state => {
Expand Down Expand Up @@ -72,6 +72,7 @@ function splitListAt(tokens, index, TokenConstructor) {
const openList = new TokenConstructor('bullet_list_open', 'ul', 1)
openList.attrSet('class', 'contains-task-list')
openList.block = true
openList.markup = tokens[index].markup
tokens.splice(index, 0, closeList, openList)
}

Expand Down
12 changes: 12 additions & 0 deletions src/nodes/BulletList.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,18 @@ const BulletList = TiptapBulletList.extend({
return this.parent().map(rule => Object.assign(rule, { preserveWhitespace: true }))
},

addAttributes() {
return {
...this.parent?.(),
bullet: {
default: '-',
rendered: false,
isRequired: true,
parseHTML: (el) => el.getAttribute('data-bullet'),
},
}
},

addInputRules() {
return [
listInputRule(
Expand Down
14 changes: 13 additions & 1 deletion src/nodes/TaskList.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,20 @@ const TaskList = TiptapTaskList.extend({
},
],

addAttributes() {
return {
...this.parent?.(),
bullet: {
default: '-',
rendered: false,
isRequired: true,
parseHTML: (el) => el.getAttribute('data-bullet'),
},
}
},

toMarkdown: (state, node) => {
state.renderList(node, ' ', () => (node.attrs.bullet || '*') + ' ')
state.renderList(node, ' ', () => `${node.attrs.bullet} `)
},

})
Expand Down
16 changes: 0 additions & 16 deletions src/tests/createEditor.js

This file was deleted.

16 changes: 8 additions & 8 deletions src/tests/extensions/Markdown.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import TaskItem from './../../nodes/TaskItem.js'
import Underline from './../../marks/Underline.js'
import TiptapImage from '@tiptap/extension-image'
import { getExtensionField } from '@tiptap/core'
import createEditor from './../createEditor.js'
import { createCustomEditor } from '../helpers.js'

describe('Markdown extension unit', () => {
it('has a config', () => {
Expand All @@ -20,7 +20,7 @@ describe('Markdown extension unit', () => {
})

it('makes toMarkdown available in prose mirror schema', () => {
const editor = createEditor({
const editor = createCustomEditor({
extensions: [Markdown, Underline],
})
const serializer = createMarkdownSerializer(editor.schema)
Expand All @@ -33,7 +33,7 @@ describe('Markdown extension unit', () => {

describe('Markdown extension integrated in the editor', () => {
it('serializes marks according to their spec', () => {
const editor = createEditor({
const editor = createCustomEditor({
content: '<p><u>Test</u></p>',
extensions: [Markdown, Underline],
})
Expand All @@ -42,16 +42,16 @@ describe('Markdown extension integrated in the editor', () => {
})

it('serializes nodes according to their spec', () => {
const editor = createEditor({
const editor = createCustomEditor({
content: '<p><ul class="contains-task-list"><li><input type="checkbox">Hello</li></ul></p>',
extensions: [Markdown, TaskList, TaskItem],
})
const serializer = createMarkdownSerializer(editor.schema)
expect(serializer.serialize(editor.state.doc)).toBe('\n* [ ] Hello')
expect(serializer.serialize(editor.state.doc)).toBe('\n- [ ] Hello')
})

it('serializes images with the default prosemirror way', () => {
const editor = createEditor({
const editor = createCustomEditor({
content: '<p><img alt="Hello" src="test"></p>',
extensions: [Markdown, TiptapImage.configure({ inline: true })],
})
Expand All @@ -60,7 +60,7 @@ describe('Markdown extension integrated in the editor', () => {
})

it('serializes block images with the default prosemirror way', () => {
const editor = createEditor({
const editor = createCustomEditor({
content: '<figure><img alt="Hello" src="test"></figure><p>hello</p>',
extensions: [Markdown, Image, ImageInline],
})
Expand All @@ -69,7 +69,7 @@ describe('Markdown extension integrated in the editor', () => {
})

it('serializes inline images with the default prosemirror way', () => {
const editor = createEditor({
const editor = createCustomEditor({
content: '<p>inline image <img alt="Hello" src="test"> inside text</p>',
extensions: [Markdown, Image, ImageInline],
})
Expand Down
51 changes: 51 additions & 0 deletions src/tests/helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { createMarkdownSerializer } from '../extensions/Markdown'
import { Editor } from '@tiptap/core'

import Document from '@tiptap/extension-document'
import Paragraph from '../nodes/Paragraph'
import Text from '@tiptap/extension-text'

import createEditor from '../EditorFactory'
import markdownit from '../markdownit'

export function createCustomEditor({ content, extensions }) {
return new Editor({
content,
extensions: [
Document,
Paragraph,
Text,
...extensions,
]
})
}

/**
* Ease markdown through TipTap editor and return serialized markdown
*
* @param {string} markdown
* @returns {string}
*/
export function markdownThroughEditor(markdown) {
const tiptap = createEditor({
content: markdownit.render(markdown),
enableRichEditing: true
})
const serializer = createMarkdownSerializer(tiptap.schema)
return serializer.serialize(tiptap.state.doc)
}

/**
* Ease HTML as input through the Editor and return the serialized markdown
*
* @param {string} html
* @returns {string}
*/
export function markdownThroughEditorHtml(html) {
const tiptap = createEditor({
content: html,
enableRichEditing: true
})
const serializer = createMarkdownSerializer(tiptap.schema)
return serializer.serialize(tiptap.state.doc)
}
Loading

0 comments on commit 116f141

Please sign in to comment.